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.
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.
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.
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.
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.
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.
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
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.
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.
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.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.
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.
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.
iron_loss_estimate
Steinmetz-type iron-loss estimate. CPU, no geometry upload — supply speed, peak flux density, and a material grade from the catalog.
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.
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.
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.
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
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
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
6. Material comparison
A catalog utility: compare electrical-steel and magnet grades side by side, no geometry required.
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.
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.
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.
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)
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_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.
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().
Next steps
- Get an API key and run your first job — see Getting started.
- Understand the flagship cogging path in Motor workflow.
- Explore the 3-D lane in cufem3d and the direction of travel on the Roadmap.
- Read the hard limitations before promising a result to a customer.