Skip to main content

opensci-engine

OpenSci's local optical design engine. Design an optical system from OpenSci's public optical catalog, simulate it with a deterministic physics engine, look at it in 3D, and get a structured Local Validation record -- all on your own computer. When the design is ready to buy, the same package takes it through OpenSci's commercial service: the Customer Purchase BOM and prices, the Experimental Lab Assembly, the Order, and after payment the Detailed Assembly Drawing. This is OpenSci "Mode A", the headless Python route (the browser Designer, "Mode B", runs the same engine in a web page); the product site is https://opensci-tech.com/.

  • Pure Python for Python 3.11 or newer (3.11, 3.12, 3.13, 3.14) on Windows, Linux and macOS; depends on numpy, scipy, pydantic>=2 and shapely (the protected extra adds cryptography). No compiler, GPU or account is needed to design.
  • Same input + same engine version + same numerical settings = same result within the declared tolerance.
  • Anything outside the published models is reported OUT_OF_MODEL_SCOPE or UNKNOWN -- never PASS.
  • You, or your own Agent, operate this package. OpenSci does not provide, host or embed an Agent; any coding Agent that can run Python or a shell can drive the commands and functions below. Every command prints JSON.

Install

With uv (it selects or downloads a compatible Python by itself):

uv tool install "opensci-engine[protected]"
opensci-engine doctor

or run without installing: uvx --from "opensci-engine[protected]" opensci-engine doctor.

With pip, in a virtual environment made from Python 3.11 or newer:

python --version                                  # 3.11 or newer
python -m venv .venv
.venv/bin/python -m pip install "opensci-engine[protected]"     # Windows: .venv\Scripts\python -m pip install ...
.venv/bin/opensci-engine doctor                                 # Windows: .venv\Scripts\opensci-engine doctor

If pip reports "requires a different Python" or "No matching distribution found for opensci-engine", the interpreter is older than 3.11: use the uv command above, or create the environment from a newer Python.

Upgrading from an earlier opensci-engine (e.g. 0.3.x). The OpenSci service accepts designs validated with the version it names (a submission from an older one is refused with ENGINE_VERSION_NOT_ACCEPTED, recovery UPGRADE_ENGINE_AND_RERUN). Upgrade, then move each saved Project to the current catalog and run it again:

python -m pip install --upgrade "opensci-engine[protected]"
opensci-engine catalog sync
opensci-engine project update-catalog project.json --out project.json   # add --include-changed if it reports "unverified"
opensci-engine project run project.json --out-dir run
opensci-engine resolve run

A Project saved by an older version pins a catalog release this version cannot compare (the service no longer distributes it), so update-catalog lists its components as unverified and keeps them unchanged: add --include-changed to move them (status UPDATED_UNVERIFIED), then review the new Local Validation before you submit.

opensci-engine doctor (or python -m opensci_engine doctor) prints one JSON report: the engine version, Python and platform, package versions, whether the [protected] extra is installed, the local public optical catalog, and whether OPENSCI_API_URL and an Account token are set up. ready.local_design: true (exit code 0) means you can start designing; next_steps lists the exact commands for anything missing. The token itself is never shown. Doctor is local and offline: it does not contact OpenSci or test the connection (opensci-engine catalog check asks the catalog service, opensci-engine account status checks your token with the service). On a fresh install catalog.status is DOWNLOAD_ON_FIRST_USE, a warning, not a failure: the catalog is downloaded by the first command that needs it, or now with opensci-engine catalog sync. The [protected] extra is needed to open the Experimental Lab Assembly and the Assembly Detail of a resolution; the catalog, Projects, simulation, Local Validation and the 3D view work without it.

The public optical catalog: synchronized, versioned, offline-first

The package does not contain the product catalog. OpenSci publishes catalog releases (catalog_version, e.g. 2026-09-30.3) on its service, and the engine keeps verified copies in a local catalog store, so new products and catalog corrections arrive without a new engine release:

  • First run. The first command that needs the catalog downloads the current release (a few MB, verified by SHA-256) into ~/.opensci/catalog/ (or OPENSCI_CATALOG_DIR); one line on stderr names the release, its size and the service it came from (standard output stays JSON). After that the engine checks the service at most once an hour with a small conditional request and downloads only a release it does not have (OPENSCI_CATALOG_CHECK_INTERVAL in seconds; 0 turns automatic checks off). Offline, the stored release is used.
  • Explicit control. opensci-engine catalog status (local, no network: the last contact with the service and its time), catalog check (ask the configured service now; when it cannot be reached, up_to_date is null rather than a stale answer), catalog sync (download the current release and make it active), catalog verify (re-check the stored files). From Python: from opensci_engine import catalog; catalog.status(); catalog.check(); catalog.sync(); catalog.verify().
  • Which recovery command. catalog sync downloads the service's current release and makes it active (the usual fix); catalog sync --release V fetches one release the service still distributes (it becomes active only when no release is active); catalog use V selects a release already stored on this computer; catalog import FILE adds a release file on a computer without access to the service.
  • Offline computers. Copy a catalog release file to the computer and run opensci-engine catalog import public_optical_catalog.json.
  • Several programs at once. Agents and commands on one computer may share the catalog store; its changes are serialized by a lock file, so no release or setting is lost. If the store's index is lost, it is rebuilt from the stored releases without guessing which one was active: the next check selects the service's current release, and offline the engine reports CATALOG_ACTIVE_UNKNOWN until you choose one with opensci-engine catalog use <catalog_version> (or catalog sync / catalog import).
  • Reproducible designs. Each catalog component of a Project pins the catalog_version it was designed with, and a run uses exactly that release (fetched once if it is missing). opensci-engine project update-catalog project.json --out project.json moves a Project to the current release: components whose product is unchanged are re-pinned; changed, withdrawn and unverified products (their old release is not on this computer and cannot be obtained) are listed with next_steps; --include-changed moves changed and unverified ones too (status UPDATED_UNVERIFIED: run the Project again and review the result). Run an updated Project again before you submit it.
  • The service is OPENSCI_CATALOG_URL, else OPENSCI_API_URL, else https://opensci-tech.com/. If the service publishes a release in a newer catalog format than this engine reads, catalog status / doctor say ENGINE_UPGRADE_REQUIRED and the stored release stays in use until you upgrade.
opensci-engine catalog sync                     # first run (or let the first design command do it)
opensci-engine catalog status                   # active release, stored releases, last check
opensci-engine catalog import catalog.json      # an offline computer: use a release file you copied
opensci-engine catalog use 2026-09-30.3         # make a stored release the active one (no network)

Quick start

opensci-engine catalog list --category LENS --wavelength-nm 780 --limit 20   # products usable at 780 nm (paged rows)
opensci-engine catalog show OS-OPT-...                            # one product: specifications, surfaces, band, geometry
opensci-engine project example --kind beam_expander > project.json   # a complete two-lens reference design to copy and edit
opensci-engine project run project.json --out-dir run             # simulate; exit code 0 PASS, 1 FAIL, 2 UNKNOWN, 3 OUT_OF_MODEL_SCOPE
opensci-engine view run                                           # the 3D Optical Simulation View in a local browser page
opensci-engine view run --snapshot shots                          # or PNG views + scene_summary.json, without a browser
opensci-engine project verify run                                 # re-check the run directory's hashes and bindings

Reference designs (project example --kind ...): focus (a single lens), folded (a fold mirror and a lens), beam_expander (two-lens telescope), relay_4f, folded_expander, dichroic_routing (two wavelengths split by a dichroic mirror), polarization (waveplate + polarizer) and two_beam_interference (one laser split into two arms that cross on a plane: fringe period, visibility and coherence margin). Each is built from the active catalog release by query.

Interference: two beams of one source interfere within its coherence length. Declare it on the source model, as linewidth_nm (spectral FWHM) or coherence_length_mm (one of the two). Without it, fringe visibility, peak irradiance and the coherence metrics are not computed, and a target on one of them is UNKNOWN; fringe period, path difference and overlap do not need it. Beams of two different source components are mutually incoherent.

The same from Python:

import tempfile
from opensci_engine.local import example_project_of_kind, load_public_catalog, run_optical_project, verify_run_artifacts
from opensci_engine.viewer import render_snapshots

catalog = load_public_catalog()                              # the active catalog release (local catalog store)
print(catalog.catalog_version, len(catalog.products), "products")
lens = catalog.select(category="LENS", form="PLANO_CONVEX_LENS", wavelength_nm="780")[0]
print(lens.optical_sku, "|", lens.display_name, "|", lens.display_name_zh_cn)

project = example_project_of_kind("beam_expander")           # a ProjectDocumentV2: source -> L1 -> L2 -> output plane
run = run_optical_project(project, output_dir=tempfile.mkdtemp())   # or a JSON document / JSON text / file path
print(run.status.value, [(t.target_id, t.status.value, round(t.value, 3)) for t in run.result.targets])
print(run.local_validation.validation_status.value, run.local_validation.input_hash.digest[:12])
assert verify_run_artifacts(run.artifacts.directory) == ()
render_snapshots(run.artifacts.directory, "shots")           # iso / top / front / side PNGs, scene_summary.json, legend.md

run.status is the outcome, run.result the full Engine result, run.local_validation the LocalValidationRecordV1, run.optical_view the 3D scene and run.artifacts.paths the written files. One run writes one directory:

File What it is
manifest.json start here: validation / simulation status, per-target status, Project / catalog / Engine identities and hashes, retained DOFs, the file list with SHA-256, and the binding checks
project.json the ProjectDocumentV2 that was run
engine_request.json the Engine ValidationRequest lowered from it (opensci-engine validate can re-run it)
simulation_result.json the Engine ValidationResult: target values and statuses, beams at each observation plane, paths, issues
local_validation.json the LocalValidationRecordV1: Project hash, Engine input / result hashes, Engine version and build id, optical SKUs + catalog version + simulation model, retained DOF intent, target outcomes, simulation and validation status
optical_scene.json the Optical Simulation View as JSON (opensci-engine schema optical-scene)
optical_scene.glb the same view as glTF 2.0: opensci-engine view shows it; any glTF viewer reads it too (nodes carry part classes and ids)

All files come from one Engine execution: the scene and the record carry the same Engine input and result hashes, and verify checks that. The view shows the optical elements with their design geometry, the sources, the Engine-traced chief and pupil rays, and the observation / target planes with the beam footprints. The rays are real rays traced through every published surface (the drawn pupil rays are the Engine's outer equal-power ring, just outside the 1/e² radius), so they show the lenses' real aberrations; the Gaussian beam numbers (waist, radius) are paraxial, in simulation_result.json and the footprints. Where the rays spread more than twice as wide as the Gaussian beam allows (an aberration-dominated focus), the Engine reports that beam's Gaussian numbers as OUT_OF_MODEL_SCOPE (GAUSSIAN_ABERRATION_DOMINATED) and pupil_rms_radius_mm gives the rays' own spot.

Reading the outcome. PASS / WARNING: every target met (WARNING lists issues worth reading; commercial resolution accepts a run whose Local Validation is PASS, so resolve the listed issues first). FAIL: a target was missed or the beam was lost -- see the targets and issues. UNKNOWN: something could not be evaluated. OUT_OF_MODEL_SCOPE: the question is outside what the published models answer (for example a wavelength outside a product's band or in a dichroic's transition gap, a coating met beyond its published angle of incidence by the chief ray, part of the beam falling on an element its chief ray misses, light leaving or crossing an element through its edge, or an aberration-dominated focus; run.model_scope_issues, the Engine issues and manifest.json say which element, surface and value) -- never treat it as a pass. A Project that cannot be simulated as given is refused before anything runs (LocalRunError; the CLI prints {"status": "ERROR", "problems": [...]} and exits 65, and writes no run directory) with structured problem codes such as OPTICAL_SKU_NOT_PUBLISHED, PRODUCT_ROLE_MISMATCH or SOURCE_MODEL_MISSING. ERROR is not a result status: there is no result to report.

Writing your own Project. Start from opensci-engine project example (or example_project().payload() in Python) and edit it; opensci-engine schema project prints the JSON Schema and print(opensci_engine.local.__doc__) explains every part (design frame, poses, sources, DOFs, observations, targets, where to expect the focus). In short: components are optical elements -- catalog products by OS-OPT-* SKU and your own sources with an explicit Gaussian source_model (wavelength, power, 1/e² waist radius and position, M², polarization); each has a nominal_pose (mm, unit quaternion w, x, y, z; local +Z is the optical axis, a catalog lens frame starts at its first surface vertex and light enters from local -Z) and optional retained_dofs (Tx..Rz, MANUAL or NUMERICAL: which degrees of freedom stay adjustable by hand or by a numerically controlled actuator). The design frame is right-handed, in mm, with +Z up; the examples lay the beam along +X. observations are planes where beams are measured (every observation reports its beams in simulation_result.json, target or not); targets put a metric (opensci_engine.local.target_metrics(); help() on it gives units and sign conventions) on an observation with at least one bound. Ids you choose (instance_id, observation_id, target_id) are copied verbatim into every artifact. Mounts, posts, stages and the breadboard are not part of a design: OpenSci configures them for each design at commercial resolution.

The catalog and the model basis

opensci-engine catalog list / load_public_catalog() give the active release of the OpenSci optical catalog: lenses (plano-convex / -concave, bi-convex / -concave, meniscus, best-form, cemented achromatic doublets), flat and concave mirrors, windows, plate beamsplitters, dichroic mirrors, edge / band / notch / neutral-density filters, half- and quarter-wave plates and linear polarizers. Every product has its specifications, published simulation model and design geometry, an English name (display_name) and a Simplified Chinese name (display_name_zh_cn); optical_sku (OS-OPT-...) is the product identity. On Windows, set PYTHONIOENCODING=utf-8 to see the Chinese names directly in catalog list output; otherwise they are printed as JSON \u escapes.

Orderable vs simulation-only. Every product states its commercial_readiness: ORDERABLE (OpenSci supplies it in an assembled system) or SIMULATION_ONLY (available for design and simulation; a Project that uses one cannot be ordered). opensci-engine catalog list shows the readiness in each row.

Model basis.

  • Surfaces are plane or spherical; lenses and windows are traced surface by surface through their prescription with the dispersion of their glass (SURFACE_PRESCRIPTION); mirrors and beamsplitters answer with their specified coating envelope (SPECIFICATION_ENVELOPE); filters, waveplates and polarizers are ideal thin elements (IDEAL_THIN_ELEMENT, Jones matrices).
  • Rays follow each beam's chief ray plus deterministic pupil samples, with one optional Fresnel reflection per interface.
  • Gaussian beams are paraxial (x/y-independent q-parameters); polarization is fully polarized Jones calculus; interference is an analytic two-beam model; materials are evaluated at their catalogue temperature.
  • Wave-optics quantities (propagation through apertures and pinholes, PSF, MTF, far-field patterns), stray light and scattering are reported OUT_OF_MODEL_SCOPE.

Look at your result in 3D

opensci-engine view run opens the run's Optical Simulation View in your browser. The page is served only to this computer (127.0.0.1, a free port, a private random path) and stops with Ctrl+C. Every element sits exactly where your design puts it, in millimetres with +Z up, coloured by kind. Main beams are drawn thick; weak branches such as a leak through a dichroic coating or a ghost reflection are thin and dashed. Use the presets (iso, top, front, side, along the beam), click a part for its id, name, SKU and size, toggle classes and beams, and switch between English and Chinese.

  • --no-browser prints the local address.
  • --write-html view.html writes one self-contained file.
  • --snapshot shots writes PNG images (orthographic, with labels, legend, axes and scale bar) plus scene_summary.json (parts by class with ids and bounding boxes in mm, beam paths, camera presets) and legend.md, for an Agent that works without a browser.

From Python: opensci_engine.viewer.view_run("run"), render_snapshots("run", "shots"), scene_summary("run"). After commercial resolution, view_assembly(preview) shows the Experimental Lab Assembly from memory -- each part coloured by class on the breadboard with the beam through it; nothing of the assembly data is written to disk.

From design to Order and Detailed Assembly Drawing

Designing, simulating and Local Validation need no account. When a design is ready to buy, opensci-engine talks to the OpenSci Commercial Service for you: resolution, prices, the Order, the payment report, the Experimental Lab Assembly and the Detailed Assembly Drawing. The same workflow is available from Python (opensci_engine.client) and from the command line.

1. Point the engine at OpenSci and give your Agent its own token

OpenSci provides your Account owner credential and the Commercial Service address. The owner credential (account:token:manage) manages tokens and nothing else; use it to give your Agent a token of its own:

export OPENSCI_API_URL=<your OpenSci service address>
opensci-engine account token create --profile agent --label "my agent" --save --token-file owner-token.txt
opensci-engine account status        # organization, scopes, expiry, what the token allows

--save writes the new token to ~/.opensci/token, readable only by you, and does not print it. The engine finds the token in this order: --token-file PATH (commands) or the token= argument (Python), OPENSCI_TOKEN, OPENSCI_TOKEN_FILE, then ~/.opensci/token. A token is never a command-line value.

Profiles: agent lets your Agent resolve, view the Experimental Lab Assembly, create the Order, report the bank transfer, obtain the Assembly Detail and upload and read drawings; review resolves, views the Experimental Lab Assembly and reads Orders and drawings. opensci-engine account token rotate --issuer-token-file owner-token.txt replaces the token in use, opensci-engine account logout revokes it at once and deletes its token file, and account token list / account token revoke TOKEN_ID manage the others.

2. Resolve, inspect, order

opensci-engine project run project.json --out-dir run
opensci-engine resolve run                                  # resolution_id, Customer Purchase BOM, prices, assembly configuration
opensci-engine resolution show RESOLUTION_ID --locale zh-CN # the same for people (zh-CN or en)
opensci-engine assembly preview RESOLUTION_ID --view        # the Experimental Lab Assembly: checked here, shown in 3D
opensci-engine account address list                         # the shipping addresses (mainland China), the default first
opensci-engine account address add --recipient 张三 --phone 13800138000 --province 广东省 --city 深圳市 \
    --district 南山区 --street "科技园路 1 号"                 # add one (the first becomes the default)
opensci-engine order create RESOLUTION_ID                   # the Order: Order Number, total, quotation, agreement, payment
opensci-engine order create RESOLUTION_ID --address ADDRESS_ID  # ... shipped to another address of the list
opensci-engine order show ORDER_ID --locale zh-CN           # also --document quotation | contract

The resolution lists the OpenSci products of your system with quantities and current prices, and the assembly configuration: how each retained degree of freedom is provided (adjustable as designed, adjusted by hand where numerical control was requested, or fixed), the breadboard, and configuration notes. A token with the agent profile is the authorization to create the Order: order create creates it directly. It ships to the default address of your organization's address book, or to --address ADDRESS_ID; ask the person which address to use. With no address at all, order create is refused with SHIPPING_ADDRESS_REQUIRED (recovery ADD_SHIPPING_ADDRESS): add one with account address add (editing and deleting addresses is done on the OpenSci Account website). The Order keeps a copy of the address. Present the Order Number, the total, the shipping address and the bank-transfer instructions to the person who pays.

To withdraw an Order -- only when the person asks, and only before a transfer is reported:

opensci-engine order withdraw ORDER_ID                      # the Order and its data are deleted

The Order, its quotation, agreement and shipping-address copy and (unless another Order uses it) the resolution are deleted; its Order Number is never used again. Tell the person it was withdrawn. To change a design after ordering: withdraw, run the design again, order again. After a reported transfer or a payment the service refuses (ORDER_NOT_WITHDRAWABLE, recovery CONTACT_OPENSCI): the person contacts OpenSci. Repeating order withdraw after a withdrawal answers ORDER_NOT_FOUND (the Order no longer exists). A resolution that was priced but never ordered is deleted after 7 days: run resolve again to order it later.

3. Pay, report, receive the Assembly Detail

Pay the full amount by corporate bank transfer with the exact Order Number as the transfer remark. When the person who paid says the transfer was made:

opensci-engine order report-transfer ORDER_ID

A report is not a confirmation: OpenSci confirms receipt of the payment. After that confirmation:

opensci-engine assembly drawing RESOLUTION_ID --out drawing   # SVG, PDF, result and manifest in drawing/, uploaded
opensci-engine artifacts list RESOLUTION_ID
opensci-engine artifacts download SET_ID ROLE --out FILE

Before the confirmation assembly drawing exits with code 75 and a JSON error whose recovery is WAIT_FOR_PAYMENT_CONFIRMATION (or CREATE_ORDER_FIRST when there is no Order yet).

The same from Python

from opensci_engine.client import OpenSciClient
from opensci_engine.local import example_project, run_optical_project

client = OpenSciClient.from_environment()
run = run_optical_project(example_project(), output_dir="run")
resolution = client.submit(run)
rid = resolution["resolution_id"]
preview = client.assembly_preview(rid)                  # opened in memory
validation = client.validate_assembly(preview)
order = client.create_order(rid)["order"]
# client.withdraw_order(order["order_id"])  # only when the person asks, before a transfer is reported
# ... the customer pays; when they say the transfer was made:
client.report_bank_transfer(order["order_id"])
# ... after OpenSci has confirmed the payment:
drawing = client.assembly_drawing(rid, "drawing", preview=preview)
client.upload_assembly_results(rid, drawing=drawing, preview=preview)

Repeating a call is safe: submissions, Orders, payment reports and uploads carry an idempotency key derived from their input, so a repeat returns the first result (replayed: true). Every failure is an OpenSciApiError with code, message, details, recovery (what to do next), http_status and request_id.

The Order's assembly data on your machine

The Experimental Lab Assembly and the Assembly Detail are delivered encrypted for one Project and opened in memory; the engine writes no copy of them. It writes what you ask for: the run directory, the validation JSON (--out), the drawing files (--out DIR), snapshot images, and your token file (--save, readable only by you). Use the assembly data for viewing, checking and assembling that Project and for its Detailed Assembly Drawing; do not redistribute it. Keep your token out of chats, logs and shared files; if it leaks, opensci-engine account logout revokes it.

Exit codes of the commercial commands: 0 done, 1 diagnostic drawing, 64 usage / file error, 65 unusable local input or delivery, 67 refused by OpenSci, 69 OpenSci unreachable, busy or rate-limited (recovery RETRY_LATER: send the same request again after retry_after_seconds), 75 not available yet (e.g. the Assembly Detail before the payment is confirmed), 77 token missing, expired, revoked or without the needed scope, 78 OPENSCI_API_URL missing.

Send feedback to OpenSci

When something did not work while you were doing what the user needed, when a feature is missing, or when this documentation was missing or wrong, send it to OpenSci. Any OpenSci Account token works (Agent or Review profile):

opensci-engine feedback submit --category PROBLEM     --summary "order create refused although an address exists"     --details-file feedback.md     --error-code SHIPPING_ADDRESS_REQUIRED --request-id REQUEST_ID --resolution-id RESOLUTION_ID

--category is PROBLEM, FEATURE_REQUEST or DOCUMENTATION; --summary is one line (5 to 200 characters); --details TEXT or --details-file FILE (UTF-8, - for standard input; 1 to 8000 characters) says what the user needed, the commands you ran, what happened and what you expected. The engine version, the Python runtime and the active local catalog release are added; --order-id, --command, --locale and --agent NAME (default: OPENSCI_AGENT_NAME) add more context. It prints the receipt {"feedback_id", "received_at", "status": "RECEIVED", "replayed"}; sending the same feedback again returns the same receipt. From Python: client.submit_feedback(category=..., summary=..., details=..., context={...}).

One problem or suggestion per submission. Include no tokens, passwords, payment data or personal data beyond what the problem needs (text holding an Account token is refused before anything is sent; the service refuses credential-shaped text with FEEDBACK_INVALID, exit 67). Tell the user what you sent. At most 10 submissions per token per hour and 50 per organization per day: above that the service answers FEEDBACK_RATE_LIMITED (exit 69, recovery RETRY_LATER, retry_after_seconds).

Working with package files

opensci_engine.assembly, opensci_engine.assembly_drawing and opensci_engine.client_artifacts also work on package objects and files directly: load_assembly_preview(source) verifies a package (manifest, digests, schema, geometry) and validate_assembly_layout(package) runs the local assembly check (AssemblyLocalValidationV1); generate_assembly_drawing(preview, detail) draws; validation_artifact_upload / drawing_artifact_upload build the upload (manifest + exact file bytes) that the artifact routes accept. The opensci-engine assembly verify | validate | draw | verify-drawing commands do the same on files.

Low-level Engine API

Below the design workflow is the stateless Engine itself: validate(request) on a ValidationRequest (3D geometric optics, Gaussian beams with x/y-independent q-parameters, Jones polarization, analytic two-beam interference, 2.5D layout, control / recoverability analysis), opensci-engine validate request.json --pretty on the command line. Build a scene programmatically with the factories in opensci_engine.builders:

from opensci_engine import builders as B
from opensci_engine.contracts import ProjectSnapshot, Target
from opensci_engine import ValidationRequest, validate

project = ProjectSnapshot(
    components=(
        B.laser("L", wavelength_nm=532.0, waist_radius_mm=1.0, position=(0, 0, 20), direction=(1, 0, 0)),
        B.thin_lens("Lens", focal_length_mm=100.0, clear_radius_mm=12.7, position=(10, 0, 20), axis=(1, 0, 0)),
    ),
    observations=(B.observation_plane("focus", position=(110, 0, 20), normal=(1, 0, 0), radius_mm=5.0),),
    targets=(Target(target_id="w", metric="beam_radius_mm", observation_id="focus", maximum=0.05),),
)
result = validate(ValidationRequest(project=project))
print(result.status.value, result.targets[0].value)    # the focused 1/e² beam radius in mm

Public API

Object Purpose
opensci_engine.local local pure-optical design workflow: public catalog, run_optical_project, run directory, verify_run_artifacts, update_project_catalog
opensci_engine.catalog the local catalog store: status, check, sync, verify, import_release
opensci_engine.viewer first-party local 3D viewer: view_run, view_assembly, render_snapshots, scene_summary
opensci_engine.client OpenSciClient: the commercial workflow with your Account token (resolution, Order, payment report, assembly data, drawing, artifacts, tokens)
opensci_engine.optical_view the Optical Simulation View builder and GLB writer (used by run_optical_project)
opensci_engine.assembly local assembly check of an Assembly Preview Package
opensci_engine.assembly_drawing local Detailed Assembly Drawing (SVG / PDF + result / manifest) from a preview + detail package
opensci_engine.protected_delivery open an encrypted assembly delivery in memory (extra [protected]); used by the client
opensci_engine.client_artifacts validation_artifact_upload / drawing_artifact_upload: the artifact upload (manifest + files, multipart parts)
validate(request) / validate_json(text) pure function: request -> ValidationResult (never raises for physical / contract validation outcomes represented by the result model)
validate_with_ray_paths(request) / trace_ray_paths(request) the same single run plus a RayPathTrace: chief and pupil sample ray polylines of every traced path; input_hash / trace_hash equal the run's manifest
ValidationRequest, ProjectSnapshot, EngineConfiguration, NumericalConfig inputs (Pydantic v2, JSON friendly)
ValidationResult, ValidationIssue, ValidationManifest outputs (finite numbers only, structured issues, hashes)
opensci_engine.builders element factories producing contract objects
opensci_engine.compare.compare_results cross-runtime comparison within cross_runtime_rel_tol/abs_tol
opensci-engine doctor / catalog / project / view / account / resolve / resolution / order / assembly / artifacts / schema / validate / compare command line (opensci-engine --help)

Status vocabulary: PASS, WARNING, FAIL, UNKNOWN, NOT_APPLICABLE, OUT_OF_MODEL_SCOPE. Design CLI exit codes: 0 PASS/WARNING/NOT_APPLICABLE, 1 FAIL, 2 UNKNOWN, 3 OUT_OF_MODEL_SCOPE, 64 usage error, 65 a Project or catalog that cannot be simulated as given, or an assembly package that does not verify, 66 project verify found an inconsistent run directory / assembly verify an invalid package.

The "never raises" guarantee above applies to the validate() / validate_json() entry points: physical and contract-validation outcomes are always represented by the ValidationResult model, never raised as exceptions. Direct construction of the frozen Pydantic contract models (e.g. builders.laser(wavelength_nm=float("nan")) or SourceSpec(...)) can still raise a Pydantic ValidationError before those entry points are called, because the contract models deliberately set allow_inf_nan=False. Pass such input through validate_json (or the CLI) to receive it as a structured FAIL / INVALID_INPUT result instead.

Conventions

Right-handed 3D, lengths mm, wavelengths nm (vacuum), angles degrees at the API, power W, w = 1/e² intensity radius. Element local +z = optical axis; surface normals are explicit; Jones vectors live in a transported transverse basis (e1, e2), e1 × e2 = d. E ∝ exp[i(k·r − ωt)]. Every numerical tolerance is a documented field of NumericalConfig (help(opensci_engine.NumericalConfig)); results record the configuration version they were computed with. input_hash / result_hash are SHA-256 integrity and reproducibility digests (results quantized to 9 significant digits): they carry no secret and prove nothing about who computed a result.

License

OpenSci Engine is proprietary software, distributed free of charge through PyPI under the OpenSci Engine License (LicenseRef-OpenSci-Engine; the full text is LICENSE.txt, with NOTICE.txt, in every wheel and source distribution). It is not open-source software.

  • Free to download and use, including for research, education, internal engineering and commercial research and development, and by your own AI agents and tools.
  • Your outputs are yours: designs, results, drawings, reports and bills of materials you produce with it can be used, published and shared freely.
  • Without written authorization from OpenSci the software itself may not be redistributed or mirrored, resold or sublicensed, repackaged into another SDK or package, or offered as the core of a competing software product or service, and its notices may not be removed.
  • Third-party dependencies and bundled components keep their own licenses.

Metadata

Release files for opensci-engine 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for opensci-engine 0.4.0
File Size Uploaded Provenance Actions
opensci_engine-0.4.0.tar.gz 679.3 kB Without provenance Details for opensci_engine-0.4.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for opensci-engine 0.4.0
File Interpreter ABI Platform Actions
opensci_engine-0.4.0-py3-none-any.whl Python 3 none any Details for opensci_engine-0.4.0-py3-none-any.whl

Total release size: 1.5 MB

Release files / opensci_engine-0.4.0.tar.gz

Download URL opensci_engine-0.4.0.tar.gz
Size 679.3 kB
Tags Source
SHA-256 checksum
How to use checksums
c050b657f9ae008698c1e2c11b8a8b35fa44fcec41706f2f5147c8220388d003
BLAKE2b-256 checksum
How to use checksums
504b6c3d8cb609472b37311a115df8cefecfe6eb1a07909eda7964d7bfc95489
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release files / opensci_engine-0.4.0-py3-none-any.whl

Download URL opensci_engine-0.4.0-py3-none-any.whl
Size 780.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d7d514e8663236e89925933569a996464c430f2d5081ea38d16154c585a490f1
BLAKE2b-256 checksum
How to use checksums
a719d6ca39ed2f7b10ecbd9b38222f8cb4e6d232203dcd4d8e419db5e60c432b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Security for opensci-engine 0.4.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page