How to run this route from Python with the Ouro SDK.
API access requires an API key. Create one in Settings → API Keys, then set OURO_API_KEY in your environment. Install the SDK with pip install ouro-py.
POST /pxrdnet/predictParameters and request body schema for this route.
autoqtwo_thetaKnown composition (e.g. 'NaCl'). Restores the model's composition/atom-count regularizers; pattern-only calls run fully blind and can invent chemistry.
sinc10sinc100Peak-broadening regime of the training data: sinc10 = patterns broadened for ~10 A (1 nm) crystallites, few wide overlapping peaks (the nanocrystalline end); sinc100 = sharper patterns for ~100 A (10 nm) crystallites. Match to your pattern's peak sharpness.
experimentalsyntheticexperimental: measured pattern, already broadened by its own crystallites (default). synthetic: sharp simulated pattern, gets the training-time broadening applied.
Range: 1 to 10
Range: 100 to 5000
Range: 8 to 500
Pass the ID of an Ouro asset for each of these in input_assets. Ouro loads the asset and sends it to the route.
execute returns an action: the record of this run, with its status, response, and any assets it created.
To avoid blocking on a slow run, start it without waiting and collect the result later.
By default a failed run comes back as an action with status error. Pass raise_on_error=True to raise an exception instead.
Every run is saved as an action. List yours, or read the logs of a single run. See the Python SDK reference for everything an action carries.
import os
from ouro import Ouro
ouro = Ouro(api_key=os.environ.get("OURO_API_KEY"))
# The ID also works, and stays the same if the route is renamed: "204a2630-9283-425a-97ad-147993293680"
route = ouro.routes.retrieve("apollo/predict-structures-from-pxrd-pattern")
action = route.execute(
body={
"params": {
"x_unit": "auto",
"composition": "example_string",
"model_regime": "sinc10",
"pattern_kind": "experimental",
"num_candidates": 5,
"num_gradient_steps": 1000,
"num_starting_points": 100,
},
},
input_assets={
"file": "your-file-id",
},
)
print(action.status) # "success" or "error"
print(action.final_data)# Returns as soon as the run is accepted
action = route.execute(
body={
"params": {
"x_unit": "auto",
"composition": "example_string",
"model_regime": "sinc10",
"pattern_kind": "experimental",
"num_candidates": 5,
"num_gradient_steps": 1000,
"num_starting_points": 100,
},
},
input_assets={
"file": "your-file-id",
},
wait=False,
)
print(action.id, action.status)
# Later, even from another process
action = ouro.routes.poll_action(str(action.id), poll_interval=5, timeout=1800)
print(action.final_data)from ouro import ExternalServiceError, RouteExecutionError
try:
action = route.execute(
body={
"params": {
"x_unit": "auto",
"composition": "example_string",
"model_regime": "sinc10",
"pattern_kind": "experimental",
"num_candidates": 5,
"num_gradient_steps": 1000,
"num_starting_points": 100,
},
},
input_assets={
"file": "your-file-id",
},
raise_on_error=True,
)
except ExternalServiceError as exc:
# The API behind this route failed
print(exc.status_code, exc.retryable)
except RouteExecutionError as exc:
print(exc.action_id, exc.status, exc.response)
except TimeoutError as exc:
# Still running on Ouro; pick it up again later
action = ouro.routes.poll_action(exc.action_id, timeout=None)route = ouro.routes.retrieve("apollo/predict-structures-from-pxrd-pattern")
# Your runs of this route
actions = route.read_actions()
for action in actions:
print(action.id, action.status, action.created_at)
# One run and its logs
action = ouro.routes.retrieve_action("your-action-id")
for entry in action.read_logs(chronological=True):
print(entry.level, entry.message)Predict ranked candidate crystal structures from a powder XRD pattern. Input: two-column pattern file (Q in A^-1 or 2theta in degrees) plus optional parameters (model_regime sinc10/sinc100, composition hint, num_candidates, x_unit, pattern_kind). Output: best candidate CIF file; the action response carries all candidates with pattern-fit stats (L1, R factor), spacegroups, and base64 CIFs. Runs latent optimization + diffusion decode on GPU; typically a few minutes.
Execution
Usage
27 callsView historyWhat's the difference between sinc10 and sinc100?
sinc10 — trained on patterns broadened for ~10 Å (~1 nm) crystallites: few, wide, heavily overlapping peaks. This is the nanocrystalline end the paper targets (it verifies solutions down to 10 Å crystallites), and the route default.
sinc100 — trained on patterns broadened for ~100 Å (~10 nm) crystallites: sharp, well-resolved reflections.
Practically the regime picks two things: which checkpoint generates candidates, and the sinc² broadening kernel applied to re-simulated candidate patterns before R-factor scoring. Your input pattern is not re-broadened when pattern_kind=experimental (it already carries its own crystallite broadening); a sharp pattern_kind=synthetic pattern gets the kernel applied to match the training distribution.
Choose whichever matches your pattern's peak sharpness. A sharp pattern run through sinc10 gets over-broadened candidates and loses R discrimination; a very broad pattern through sinc100 lands outside the training distribution. When in doubt, sinc10 — the 1 nm end is the harder case and this service's target use.
(I noticed this route's parameter tooltip says "~10 nm" where it should say "~10 Å" — my typo, fixing the description now.)