PKR Core
Technical Explanation 5 min read

Two days and two builds later, the same numbers came back

A number you put in a report has to still mean something next quarter. The same recipes were sent to the PKR Core API twice, two days and one deployment apart. Every effective property came back to the last digit it had before, and the figures the server drew came back as the same files, byte for byte.

  • Analyze Properties
  • Automate Workflows
  • Build Structures
Scatter plot of porosity against volume fraction for five cases, returned unchanged by a second run of the same sweep.

What you can do

You can treat a PKR Core result as something to re-derive rather than something to archive. Generation is seeded and the solvers are deterministic, so a recipe plus a seed is a complete description of a structure and of every property measured from it. A baseline from three weeks ago does not need its voxels kept anywhere. It needs its recipe kept.

  • POST /api/v1/generate with a fixed seed returns the same structure. A few hundred bytes of JSON is enough to get it back.
  • The property solvers return the same value for the same structure. There is no run-to-run scatter to average away.
  • Figures the server draws come back identical — cross sections from export-image-stack, the trend chart from parametric-study. A plot in a report can be regenerated instead of stored.
  • GET /api/v1/healthz reports deployedSha, the build that answered. A result can be labelled with the version that produced it.

Why it matters

Comparing two candidates measured weeks apart only works if the platform contributes nothing to the difference between them. Otherwise every comparison carries an unknown amount of drift. The only safe move is then to recompute the baseline every time, which is exactly the work you were trying to avoid.

When the service contributes zero, whatever spread you do see belongs to your structure. That is a number worth knowing on its own. In this run, a randomly packed 32³ box has no preferred direction, yet it returned conductivities of 4.4558, 4.2561 and 4.1198 W/m·K along x, y and z. That is about 8 % between the fastest and the slowest axis, purely from having a finite number of spheres in a small box. It is the floor under any comparison at this size. If the service drifted too, you could not tell the two apart.

What was compared

The same showcase script ran on 2026-09-04 and again on 2026-09-06, against api.pakericore.app. The deployed commit was 1162757 the first time and ebf9efc the second. Same three example recipes at 64³, packings raised to 45 % solid at 15 % overlap, solid phase alumina at 30 W/m·K, and the same closed-form validation fixtures.

QuantityPublished from the 2026-09-04 runMeasured 2026-09-06
Particle packing, conductivity (W/m·K)19.2119.211442684614628
Fiber packing, conductivity (W/m·K)21.4621.455226746729483
Foam-like, permeability (µm²)7.437.4336097575724125
Two slabs in parallel, x (W/m·K)50.4907450.49074205942826
Random packing, x (W/m·K)4.45584.4558288976859135

Every value agrees to every digit that was published. The solid fractions agree exactly as well: 0.4503746032714844 for the particle packing, the same binary fraction both times. Within this run, generating one recipe twice with the same seed gave a relative difference of exactly zero. Not "within tolerance". Zero.

The images are the sharper test. A rounded table can hide a small change. A PNG cannot. Every figure published with the earlier articles has the same SHA-256 as the file downloaded from the API two days later.

Artifact the API returnedSHA-256, first 12 hex digits — identical in both runs
Particle-packing cross section (PNG)a50f1cd34b38
Fiber-packing cross section (PNG)5ca7fd47f266
Foam-like cross section (PNG)c07da71b3526
Two-slab validation fixture (PNG)026a063ffd40
Capability-suite structure (PNG)720c128ae2ef
Five-point sweep trend chart (SVG)a8d0a8b046db
Scatter plot of porosity against volume fraction for five cases, falling from about 0.85 at 15 percent to about 0.45 at 55 percent.
A five-case sweep, generated and plotted server-side in one request: 1,701 ms, five points, none skipped. The SVG is the same file the earlier run downloaded — a whole batch reproduced, not just a single number.
Cross section at z=32 of the particle-packed structure: rounded solid particles filling most of the frame with pore space between them.
The particle packing at z = 32, drawn by the server at grid resolution. Same recipe, same seed, different build, same 656 bytes.

What did not repeat

Wall-clock time, and only wall-clock time. Generating the particle packing took 349 ms in the first run and 428 ms in the second. The fibers went the other way, 673 ms down to 623 ms. The whole three-structure suite was 10.3 s, then 11.0 s. Timing is a property of the machine and the load at that moment, not of your input.

That distinction has one practical consequence: never build a study whose result depends on a call fitting inside the synchronous request window. The full-grid 3d conductivity solver at 32³ returned 504 after 15.1 s in both runs. The ceiling reproduced, but as a ceiling, not as a number. Anything sitting near it is a coin flip, and the reduced solvers exist precisely so that you do not have to sit there.

Send the recipe, not the handle

A structureId is a server-side handle with a lifetime. It is not the identity of the structure. Registering a structure once with storeStructure and passing that id to every later call does keep request bodies small. But in the capability run, ten analysis calls came back 404 structure_not_found — "Stored structure is unknown or expired". Every one of them arrived after the 15-second timeout above had elapsed.

The recipe is the identity. In the same run, one POST /api/v1/workflows/run carried the recipe itself, with no stored id anywhere in the request. It generated the structure and returned 11 of the 12 requested outputs in 3.8 s. The one that did not land was the CO₂ adsorption step, which reported unstable_timestep as a named step error rather than failing the whole request. Eleven results and one explained gap beats no results.

So the durable record of a measurement is four small things:

  • the recipe, including its seed
  • the material constants it was solved with (GET /api/v1/materials)
  • the analysis method name
  • the deployedSha that answered

Keep those and the numbers come back. Keep only a structureId and you have kept a receipt for something that has been thrown away.

Try it in PKR Core.

Open PKR Core