Docs / Examples & recipes

Examples & recipes

Paste-runnable client-SDK recipes for the main cufemlab analysis workflows — from the flagship FEMM/GetDP cross-checked 2-D cogging workflow to the 3-D field-validation lane — each with what it computes, how it is validated, and the exact code to run it.

Before you run. Install the client with pip install cufemlab-client, then set CUFEMLAB_API_KEY from your API keys page. The base URL defaults to https://app.cufemlab.secrotec.nl — you never pass it explicitly. Every recipe follows the same shape: Client(api_key)create_project() → optional upload_file()analyze()job.wait()job.result(). The snippets below omit max_minutes so each analysis uses its per-type default, and pass gpu=True only for the GPU analyses. New to the flow? Start with Getting started, or run these interactively in the app under New analysis.

Two kinds of number

cufemlab is deliberate about what carries an independent cross-check and what is an engineering estimate. Read every result with this distinction in mind — it is also written into each job’s result envelope.

Validated

Cross-checked results

The moving-band cogging workflow emits a per-run validation card that cross-checks the 2-D field against the open-source FEMM and GetDP solvers, citing the declared tolerance and the measured error. The legacy 2-D sweep does not — it carries no oracle card. For the flagship, citing the declared tolerance and the measured error.

read result.metrics for the card
Estimate

Engineering estimates

Operating torque (2-D) and iron loss (Steinmetz-type) are engineering estimates — useful for trends, sizing, and comparison studies, but not independently validated and shipped without a cross-check card.

treat as directional, not certified

1. Moving-band cogging torque

The flagship validated workflow: a 2-D no-load cogging analysis on a moving-band / Arkkio airgap, cross-checked against FEMM and GetDP on every run.

Validated

cogging_torque_movingband

2-D moving-band cogging torque with a per-run FEMM/GetDP validation card that cites the tolerance and the measured error. This is the recommended cogging path.

Validated range. The currently validated production range covers the 12-slot moving-band family exercised in the live validation campaign, including n_poles in {2, 4, 6} with refine_levels=3. The canonical 4-pole/12-slot anchor gives approximately 0.048069 Nm and matches independent FEMM/GetDP reference evidence within the declared tolerance. Unsupported pole/slot combinations or refine_levels below 3 may return FAIL rather than a fabricated value. The legacy cogging_sweep_2d path remains legacy/partial.

GPU · flagship validated · FEMM + GetDP card each run · .step / .stp / .iges / .stl
recipe — moving-band coggingPython
import os
from cufemlab_client import Client

client = Client(api_key=os.environ["CUFEMLAB_API_KEY"])   # base url defaults to https://app.cufemlab.secrotec.nl
project = client.create_project("PMSM cogging (moving band)")

# Moving-band cogging is parametric - no geometry upload needed.
job = client.analyze(
    project_id=project.id,
    analysis_type="cogging_torque_movingband",
    input_params={"n_poles": 4, "n_slots": 12, "Br_T": 1.20, "n_angles": 24, "refine_levels": 3},
    gpu=True,
)
job.wait(poll_interval=10)
result = job.result()

print(result.verdict, result.value)     # PASS + peak cogging amplitude (N·m)
print(result.metrics)                   # FEMM/GetDP validation card: tolerance + measured error
Reading the card. result.metrics carries the cross-check payload — the reference method, the declared tolerance, and the measured relative error against FEMM and GetDP. See Motor workflow for the reference case and how the airgap torque is integrated.

2. Cogging sweep (2-D)

The older 2-D torque-vs-angle sweep. It carries no FEMM/GetDP card, and it is superseded by the moving-band workflow above.

Legacy

cogging_sweep_2d

Legacy / partial 2-D cogging sweep. Kept for continuity and comparison; it carries a validation card, but new work should prefer cogging_torque_movingband.

GPU · legacy 2-D · no oracle card · superseded by moving band
Legacy path. cogging_sweep_2d is the earlier, partial sweep implementation. It remains live and supported, but it carries no oracle card and is not a validated path. For any new cogging study, use the moving-band workflow — it is the maintained, recommended path.
recipe — legacy cogging sweepPython
import os
from cufemlab_client import Client

client = Client(api_key=os.environ["CUFEMLAB_API_KEY"])
project = client.create_project("Cogging sweep (legacy 2-D)")

job = client.analyze(
    project_id=project.id,
    analysis_type="cogging_sweep_2d",
    input_params={"n_angles": 32, "Br_T": 1.20},
    gpu=True,
)
job.wait(poll_interval=10)
result = job.result()
print(result.verdict, result.summary)   # .summary is a dict property, not a method

3. PMSM operating torque

A 2-D operating-torque engineering estimate for a loaded PMSM — directional, not independently validated.

Estimate

pmsm_operating_torque

2-D on-load operating-torque estimate from phase current, speed, and advance angle. Good for trends and comparison; it does not carry a cross-check card.

GPU · 2-D operating-torque estimate · not independently validated
recipe — operating torquePython
import os
from cufemlab_client import Client

client = Client(api_key=os.environ["CUFEMLAB_API_KEY"])
project = client.create_project("PMSM operating torque")

geom = client.upload_file(project.id, "pmsm_2d.step")

job = client.analyze(
    project_id=project.id,
    analysis_type="pmsm_operating_torque",
    input_params={"current_a": 12.0, "rpm": 3000, "advance_deg": 15.0},
    input_file_ids=[geom.id],
    gpu=True,
)
job.wait(poll_interval=10)
result = job.result()
print(result.verdict, result.value)     # operating-torque ENGINEERING ESTIMATE (N·m)

4. Iron-loss estimate

A Steinmetz-type core-loss engineering estimate from speed, peak flux, and an electrical-steel grade.

Estimate

iron_loss_estimate

Steinmetz-type iron-loss estimate. CPU, no geometry upload — supply speed, peak flux density, and a material grade from the catalog.

CPU · Steinmetz-type estimate · not independently validated
recipe — iron lossPython
import os
from cufemlab_client import Client

client = Client(api_key=os.environ["CUFEMLAB_API_KEY"])
project = client.create_project("Iron-loss study")

job = client.analyze(
    project_id=project.id,
    analysis_type="iron_loss_estimate",
    input_params={"rpm": 3000, "B_peak_T": 1.4, "material": "M250-35A"},
)
job.wait(poll_interval=10)
res = job.result()
print(f"iron loss = {res.value} W   metrics = {res.metrics}")   # estimate, watts

5. cufem3d — the 3-D lane (CPU validation + GPU-accelerated analysis)

The 3-D lane ships as two separate analysis types. Both run the same 3-D magnetostatic edge-element (Nedelec) formulation; they differ in execution target and in what they are for.

3-D field · CPU

cufem3d_field_validation

CPU 3-D field validation utility. Imports your 3-D geometry, builds the mesh, computes the magnetic field and flux, and returns a relative-error field verdict with VTU artifacts, cross-checked against an analytic reference. Free-trial eligible.

CPU · 3-D magnetostatic (Nedelec) · externally cross-checked · free-trial · 1 credit · ≤ 5 min
3-D field · GPU

cufem3d_gpu_field_analysis

GPU-accelerated 3-D field analysis is available on compatible GPU workers. Runtime metadata reports the actual execution backend and fallback state. The solve runs on the GPU (cupy / cuSPARSE conjugate gradient) and every result carries the device, precision, convergence state, and an analytic cross-check against the magnetized-sphere reference; enabling run_reference_check (off by default) adds a CPU/GPU numerical parity check. It is fail-closed: if no GPU is available the job fails rather than silently running on CPU. Experimental — this is not an independently validated 3-D torque prediction.

GPU · 3-D magnetostatic (Nedelec) · experimental · not free-trial · 2 credits · ≤ 10 min

These are the geometry-and-field lanes, and the first steps on the roadmap toward full 3-D motor simulation. Keep current capability and roadmap clearly separated:

Available today

  • 3-D geometry import and mesh generation
  • 3-D magnetostatic edge-element (Nedelec) solve
  • GPU-accelerated 3-D field analysis on compatible GPU workers, with the actual backend and fallback state reported in runtime metadata
  • Magnetic field |B| and flux, exported as VTU
  • Relative-error field verdict per run

Maturing

  • Larger meshes and finer field resolution
  • Broader geometry and material coverage on the GPU lane
  • External validation passport for the GPU lane

Roadmap

  • Full 3-D motor torque with skew and end-effects
  • Full 3-D operating maps
recipe — 3-D field validationPython
import os
from cufemlab_client import Client

client = Client(api_key=os.environ["CUFEMLAB_API_KEY"])
project = client.create_project("3-D field validation")

# 3-D geometry (.step / .stp / .iges / .stl). CPU solve, free-trial eligible.
geom = client.upload_file(project.id, "magnet_assembly.step")

job = client.analyze(
    project_id=project.id,
    analysis_type="cufem3d_field_validation",
    input_params={"mesh_target": "medium"},
    input_file_ids=[geom.id],
)
job.wait(poll_interval=10)
result = job.result()

print(result.verdict, result.value)   # relative-error field verdict
print(result.metrics)                 # geometry / mesh / |B| / flux; VTU artifacts attached
recipe — GPU-accelerated 3-D field analysisPython
import os
from cufemlab_client import Client

client = Client(api_key=os.environ["CUFEMLAB_API_KEY"])
project = client.create_project("GPU 3-D field analysis")

# Parametric - no upload. Runs on a compatible GPU worker.
# allow_cpu_fallback=False (the default) is FAIL-CLOSED: with no GPU the job
# fails instead of silently running on CPU.
job = client.analyze(
    project_id=project.id,
    analysis_type="cufem3d_gpu_field_analysis",
    input_params={
        "mesh_n": 24,                    # 12 - 32
        "box_L": 3.0,                    # 2.0 - 4.0
        "allow_cpu_fallback": False,
        "run_reference_check": True,     # also run the CPU parity check
    },
)
job.wait(poll_interval=10)
result = job.result()

# Runtime metadata reports the ACTUAL execution backend - never assume.
meta = result.value["runtime_metadata"]
print(meta["actual_backend"])            # "gpu"
print(meta["fallback_used"])            # False
print(meta["device_name"])              # e.g. "NVIDIA GeForce RTX 5090"
print(meta["analytic_relative_error"])  # vs the analytic sphere
More on the 3-D lane. See cufem3d for the edge-element formulation, the VTU field and flux outputs, and how the relative-error verdict is computed. The GPU lane is experimental: it is the GPU execution target for the same field solve, not an independently validated 3-D torque prediction.

6. Material comparison

A catalog utility: compare electrical-steel and magnet grades side by side, no geometry required.

Utility

material_comparison

Compare electrical-steel and magnet grades drawn from the materials catalog. No upload, no GPU — a fast way to scope a grade choice before a full run.

CPU · materials-catalog utility · no geometry upload
recipe — material comparisonPython
import os
from cufemlab_client import Client

client = Client(api_key=os.environ["CUFEMLAB_API_KEY"])
project = client.create_project("Steel and magnet grades")

job = client.analyze(
    project_id=project.id,
    analysis_type="material_comparison",
    input_params={"materials": ["M250-35A", "M400-50A", "N42"]},
)
job.wait(poll_interval=10)
result = job.result()
print(result.verdict, result.summary)   # side-by-side grades from the catalog

7. Signed report

A reporting utility: turn a completed job into a deterministic, HMAC-signed PDF with SHA-256 provenance.

Utility

signed_report_generation

Deterministic, HMAC-signed PDF evidence report built from a completed job. Same inputs always produce the same signed document, with a SHA-256 provenance hash.

CPU · HMAC-signed PDF · SHA-256 provenance · deterministic
recipe — signed reportPython
import os
from cufemlab_client import Client

client = Client(api_key=os.environ["CUFEMLAB_API_KEY"])

source_job_id = "..."            # a COMPLETED job whose result you want to certify
src = client.get_job(source_job_id)

job = client.analyze(
    project_id=src.project_id,
    analysis_type="signed_report_generation",
    input_params={"source_job_id": source_job_id},
)
job.wait(poll_interval=5)
path = job.download_report("report.pdf")   # HMAC-signed PDF, SHA-256 provenance
print("Saved:", path)
Where reports land. Signed PDFs are also listed in the app under Reports. Each report embeds the sub-verdicts, the cited reference and tolerance for every check, and the provenance hash of inputs plus materials plus code.

8. Demo motor quick check

The zero-setup smoke test — the fastest way to confirm your key, project, and result flow all work end to end.

Demo

demo_motor_quick_check

A fast CPU smoke check with no geometry upload. Run this first to verify authentication and the full submit → wait → result path before spending credits on a GPU analysis.

CPU · zero-setup smoke check · good first run
recipe — demo quick checkPython
import os
from cufemlab_client import Client

client = Client(api_key=os.environ["CUFEMLAB_API_KEY"])   # base url defaults to https://app.cufemlab.secrotec.nl
project = client.create_project("Quick motor check")

job = client.analyze(
    project_id=project.id,
    analysis_type="demo_motor_quick_check",
    input_params={"notes": "first smoke check"},
)
job.wait(poll_interval=10)
result = job.result()
print(result.verdict, result.value)

Reading results & running many jobs

Every completed job exposes the same fields through job.result(): .verdict (the pass / fail or field-verdict outcome), .value (the headline number), .summary (a dict property, not a method), and .metrics (the full payload — including the FEMM/GetDP card for the validated workflows). Signed reports add job.download_report().

Concurrency. Each account has a per-user concurrency cap. Submitting a second job while you are already at the cap returns HTTP 429 CONCURRENCY_LIMIT_EXCEEDED — wait for a running job to finish, then submit the next one. Watch live progress in the app under Queue.
Credits. Paid runs draw from your credit balance; the demo and the 3-D field validation are free-trial eligible (1 credit, ≤ 5 min for the 3-D lane). GPU analyses (moving-band cogging, the legacy sweep, and operating torque) run on the GPU node; iron-loss, material comparison, signed reports, the demo, and cufem3d run on CPU — see Compute: GPU & CPU.

Next steps