Skip to content

casino-mcp 0.6.0

Latest

Choose a tag to compare

@Konjkov Konjkov released this 01 Sep 12:06

Runs are one at a time now — a second is refused while a job this server started is going,
because two CASINO runs sharing the cores make Total CASINO CPU time, and the efficiency
computed from it, stop meaning what they say. And a restart no longer has to destroy the
answer of the run before it, which matters more now that rerunning in place is the ordinary
way to work.

Behind both, the corrections that go with them: casino_results for a job whose directory had
been rerun was answering with the next run's numbers, and three of the tools that act had no
output schema at all — which is how JobState.binary declared the wrong type for five
releases without anything noticing.

pip install casino-mcp

On PyPI: https://pypi.org/project/casino-mcp/0.6.0/

Added

  • casino_wait(job_id, timeout) (casino-mcp wait): block until a running calculation
    ends, and answer with the state it ended in, plus waited and timed_out. A chain is then
    run, waited for and read back without a polling loop -- what a campaign wrote by hand was
    while pgrep -x casino; do sleep 5; done, or a status call every few seconds, each one a
    round trip through the model. The wait is bounded (600 s by default, wait_timeout in
    casino-mcp config) because a stdio server answers one call at a time, so a wait is the
    whole control plane standing still; a caller that wants longer calls again. Waiting is not
    stopping: nothing is signalled and the calculation is not touched.
  • Every tool that takes a job takes a calculation directory instead -- casino_status,
    casino_wait, casino_results, casino_stop -- and it means the newest job that ran there.
    A campaign holds directories: the scan's own loop variable is the directory it prepared, and
    the job id of the run in it is a string the caller never saw, which is why reading results
    back meant grepping out rather than asking for them. The registry answers the question, so
    nothing is written into the calculation directory to record it.
  • casino_results(job_id, fields=[...]) (casino-mcp results -f vmc.efficiency): answer
    with just the paths asked for, as one flat {path: value}. A parsed run is 10-16 kB of JSON
    and a scan over 38 directories wanting six numbers from each does not want 600 kB of it --
    which is why the campaign that prompted this grepped out instead of calling the tool. A
    path is written in the run's own keys, with four rules: vmc / opt / dmc_equil /
    dmc_stats are the last phase of that kind, opt[3] and vmc[2] the cycle CASINO itself
    numbered, phases[-1] and phases[0] a position, and anything else is a key --
    keywords.DTVMC, cpu_time, result.energy, vmc.energy.error, vmc.blocks[0].time,
    status. A path that lands on a measured value collapses to the number. A path that does not
    exist is a mistake in the question and comes back in problems naming what is there instead;
    a path that exists but holds a number CASINO never printed comes back as null with its reason
    -- the two are different things and the projection keeps them apart. The same selector is what
    a scan tool will project its table with, rather than a second one beside it.
  • casino_input(job_id) (casino-mcp input): the keywords and %blocks a calculation was
    given, as data. results answers what a run did and this answers what it was told to do, and
    the two are not the same reading: the keywords in a result are CASINO's own echo, which
    holds every default it applied -- 70 entries against the 23 a file typically sets -- and drops
    what it does not print. random_seed is one of those, and it is the keyword the question
    "can this number be reproduced" turns on. It reads a directory nothing has run in, which is
    how a prepared calculation is checked before there is a job to name it by, and for a job that
    casino_stop halted it also returns before_halt: the input the run was started from, kept
    in the registry because haltqmc -u rewrites the file in place and the rewrite is lossy.
  • casino_list_jobs(limit, workdir) filters to one directory: what a chain of runs did in one
    place, and the way to see that a directory has been run twice.
  • Runs are one at a time, and casino_run(allow_concurrent=true) is how they are not. A
    second run is refused while a job this server started is going -- not because the machine is
    busy, but because of what sharing it does to the numbers: Total CASINO CPU time counts CPU
    seconds across the MPI processes, and two jobs that landed on the same core measured 97.2 s
    of CPU against 194.41 s of real time, with efficiency wrong by the same factor and nothing
    in the output saying so. The reply on the override names what it runs beside, under
    concurrent. A job running in the same directory is refused with no override at all --
    one directory is one calculation -- and that check is asked before the .runqmc.lock one,
    which would otherwise offer unlock=true and turn the caller loose on a live calculation.
    Only jobs this server started are known: a pgrep casino over the machine is deliberately
    not done, because "something is computing" with no owner and no job id is a refusal the
    caller has nothing to answer with. So reading cpu_time against real_time afterwards is
    not a backstop but the check that holds, and it is one
    casino_results(fields=['cpu_time', 'real_time']).
  • casino_run(restart=true, keep_previous=true) (casino-mcp run --keep-previous) moves
    out to the first free out.1, out.2, ... instead of deleting it; the rest of what
    restart deletes goes as before, and the reply says where it went, under kept. The
    numbering ends up being the order the runs happened in. The archives are deliberately not in
    DEBRIS, and are not named out_part.N -- that name is runqmc's own, for the segments of a
    --continue, and it is in DEBRIS. Refused without restart: nothing is being deleted
    then. What this is really for is the casino_results fix below.

Changed

  • The job index records created_epoch beside created. A job id is only chronological to the
    second, and two runs of one directory a second apart -- which is what a scan does -- cannot be
    told apart by it. A record written before this falls back to its id, which is all it has.
  • casino_results says what it returns. Its description named energies and per-block
    numbers and nothing else, while the parser had been returning acceptance,
    correlation_time, efficiency, the optimized dtvmc, steps_per_process and the whole
    statistical-efficiency section all along — so the way to those numbers was to grep out for
    them. The docstring now lists what a phase holds, by kind, and a test holds it to the parser.

Fixed

  • casino_results for a job whose directory has been rerun answered with the wrong run's
    numbers.
    A job record held a directory, not a file, and the output was found in it by the
    name out -- which holds for exactly as long as one run has happened there. After a restart
    in place, the earlier job answered with the physics of the run that came after it, under its
    own id, with its own status and its own start time, and nothing in the reply saying so. Job
    records now name the file, casino_status reports it as out, and keep_previous moves the
    record along with the file, so each job goes on answering with what it produced. Records
    written before this read as out, which is what every one of them wrote.
  • advise no longer tells a runtype : vmc input that CASINO will not read its opt_dtvmc.
    unused placed a keyword by its prefix, and opt_dtvmc is named like an optimisation
    keyword and is a VMC one — the VMC phase's own time-step optimisation. Which phase a keyword
    belongs to is SECTIONS now; a keyword the table does not know is still placed by its prefix.
  • The trap that is real is the other way round, and advise now warns about it: dtvmc set
    while opt_dtvmc is not 0 means CASINO takes the value as a starting point and optimizes the
    step away from it, so a scan over dtvmc measures one step in every directory.
  • casino_status, casino_wait and casino_list_jobs answer again. All three return the
    JobState family, and JobState.binary declared a str while binary_stamp() has answered
    with a dict — path, exists, size, mtime — since the initial commit, so every one of
    them failed at serialization with binary: Input should be a valid string, after the
    calculation had already run. The stamp now has a model of its own, BinaryStamp, which is
    also the honest name for it: not which binary, but which build of it, the thing that tells
    results from before and after a rebuild apart. Nothing had caught this in five releases
    because the field was the one place the model named what the runtime returns and named it
    wrongly — extra='allow' waves every unnamed key through untouched — while casino_run
    declares a plain dict and hands the same stamp back correctly, and casino_results never
    fills the field in. Guarded now by a unit test that puts a real binary_stamp(), in both the
    shapes it has, through JobState; the tests that stub the runtime out call the tool as a
    plain function and never reach the output model at all.
  • The three tools that act rather than read now have an output schema too. casino_run,
    casino_prepare and casino_stop were declared -> dict[str, Any], so what reached the
    model was {"type": "object", "additionalProperties": true}: not one field name, not one
    unit, and nothing a test could compare against what the runtime actually answers. That is the
    hole binary lived in for five releases — a reply nothing describes is a reply nothing can
    check. They return Started, Prepared and Stopped now, with BinaryStamp,
    CorrelationData, GeminalPlan, Terminated and Halt under them, so a caller reading a
    stop can see that terminated.scope says whether the ranks or the whole process group were
    signalled and that halt.updated_input is what decides whether the run can be continued.
    Guarded by a test per tool that puts a real call's answer through the model that declares it,
    and by three that hold the module rather than a list: every model in it describes its fields,
    every tool answers with one of them, and every one of them is reached by a tool. The list
    this replaces named five of the fifteen models, so nothing held the ones added after it was
    written — which is the same way binary survived. What is guarded now is the annotation, not
    the three tools that happened to have the wrong one.
  • command means one thing again. casino_run answered with ' '.join(command) while
    casino_status answered with the argv under the same key, so the same name on the same
    surface had two types. It is the argv everywhere now, in casino_run and in the halt
    report: the exact arguments, which a joined string cannot be parsed back into.
  • casino_prepare no longer sends wrote: null alongside a refusal. It was there to say
    nothing had been written, which is what the refusal says.
  • parse_out no longer raises on an out with no phase in it. split_phases paired each
    phase with the one after it under strict=True, and with no phase there was still a
    sentinel to pair against, so a file that never reached VMC — a run that errstopped on a
    missing gwfn.data, say — came back as ValueError: zip() argument 2 is longer than argument 1 out of casino_results instead of as a parsed file. Which is the reading that
    matters most there: it is the run whose failure has to be looked at. block_bounds had the
    same shape for a phase cut off before it finished a block. Both answer with an empty list
    now, and the rest of the file — Started, the messages CASINO printed — is read as ever.