Ore control
Compute tasks are building blocks. You can use each one by itself, but you can also combine them to build workflows. In this example, you'll build an ore control workflow that goes like this:
- Break ties in the data.
- Calculate declustering weights.
- Calculate a CDF for the data.
- Run conditional block turning-bands simulation.
- Visualize the result.
- Use a profit function to classify blocks as ore or waste.
Starting objects
You need a few objects in your workspace to start with:
- A pointset or downhole-intervals object with drillhole data.
- A regular-3d-grid or regular-masked-3d-grid to hold the simulation results.
- A variogram model fitted to the drillhole data.
You can create those objects with the Geoscience Objects API.
This example uses a pointset called composites.json with one attribute called gold-ppm. It uses a variogram model called gold-ppm-variogram.json, targets a regular-3d-grid called simulation-grid.json.
Break ties
Start with the break ties task.
execution_response = requests.post(
"https://{hub}.api.seequent.com/compute/orgs/{org_id}/geostatistics/break-ties",
headers={"Authorization": "Bearer {token}"},
allow_redirects=False,
json={
"parameters": {
"source": {
"object": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/composites.json",
"attribute": "locations.attributes[?name=='gold-ppm']",
},
"target": {
"object": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/composites.json",
"attribute": {"operation": "create", "name": "gold-ppm-without-ties"},
},
"seed": 123,
"neighborhood": {
"ellipsoid": {
"ellipsoid_ranges": {"major": 70, "semi_major": 70, "minor": 5},
"rotation": {"dip_azimuth": 0, "dip": 0, "pitch": 0},
},
"max_samples": 40,
"min_samples": 1,
},
},
},
)
After starting the task, you need to wait for it to finish.
status = None
while status not in {"failed", "cancelled", "succeeded"}:
polling_response = requests.get(
"https://{hub}.api.seequent.com" + execution_response.headers["Location"],
headers={"Authorization": "Bearer {token}"},
)
status = polling_response.json()["status"]
time.sleep(1)
if status == "succeeded":
break_ties_result = requests.get(
polling_response.json()["links"]["result"],
headers={"Authorization": "Bearer {token}"},
).json()
When it's done, the result looks like this:
{
"message": "Break ties completed.",
"target": {
"reference": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/composites.json",
"name": "composites",
"schema_id": "/objects/pointset/1.3.0",
"attribute": {
"reference": "locations.attributes[?key=='3cc3aa58-c928-4e79-b8ca-550174bff59e']",
"name": "gold-ppm-without-ties"
}
}
}
The next steps won't show the polling code, but you can repeat the same pattern for each task.
Declustering
Next, make declustering weights with the declustering task. Declustering measures how much spatial territory each sample represents, so it works on the sample locations in your pointset. It also needs an evaluation grid to measure that influence — reuse simulation-grid.json.
execution_response = requests.post(
"https://{hub}.api.seequent.com/compute/orgs/{org_id}/geostatistics/declustering",
headers={"Authorization": "Bearer {token}"},
allow_redirects=False,
json={
"parameters": {
"source": {
"object": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/composites.json",
},
"grid": {
"object": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/simulation-grid.json",
},
"target": {
"object": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/composites.json",
"attribute": {"operation": "create", "name": "gold-ppm-declustering-weights"},
},
"neighborhood": {
"ellipsoid": {
"ellipsoid_ranges": {"major": 70, "semi_major": 70, "minor": 5},
"rotation": {"dip_azimuth": 0, "dip": 0, "pitch": 0},
},
"max_samples": 40,
"min_samples": 1,
},
"power": 2.0,
},
},
)
After waiting for the task to finish, the result looks like this:
{
"message": "Declustering completed (IDW, power=2.0).",
"target": {
"reference": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/composites.json",
"attribute": {
"reference": "locations.attributes[?key=='7b1e2c3d-4a5f-6b7c-8d9e-0f1a2b3c4d5e']",
"name": "gold-ppm-declustering-weights"
}
}
}
Apply the same polling pattern to capture this as declustering_result.
Continuous distribution
Now, make a non-parametric continuous cumulative distribution with the continuous distribution task, using your tiebroken data and declustering weights.
execution_response = requests.post(
"https://{hub}.api.seequent.com/compute/orgs/{org_id}/geostatistics/continuous-distribution",
headers={"Authorization": "Bearer {token}"},
allow_redirects=False,
json={
"parameters": {
"source": {
"object": break_ties_result["target"]["reference"],
"attribute": break_ties_result["target"]["attribute"]["reference"],
},
"weights": {
"object": declustering_result["target"]["reference"],
"attribute": declustering_result["target"]["attribute"]["reference"],
},
"tail_extrapolation": {
"upper": {"power": 0.5, "max": 99.0},
"lower": {"power": 0.5, "min": 0.0},
},
"target": {
"reference": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/gold-ppm-distribution.json",
"overwrite": True,
},
},
},
)
The result looks like this:
{
"message": "Continuous distribution calculated successfully.",
"distribution": {
"reference": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/gold-ppm-distribution.json"
}
}
Apply the same polling pattern to capture this as continuous_distribution_result.
Time to simulate! Use the conditional turning bands task with the tiebroken data and the distribution you just made.
execution_response = requests.post(
"https://{hub}.api.seequent.com/compute/orgs/{org_id}/geostatistics/conditional-turning-bands",
headers={"Authorization": "Bearer {token}"},
allow_redirects=False,
json={
"parameters": {
"source": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/composites.json",
"source_attribute": break_ties_result["target"]["attribute"]["reference"],
"target": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/simulation-grid.json",
"distribution": continuous_distribution_result["distribution"]["reference"],
"variogram_model": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/gold-ppm-variogram.json",
"neighborhood": {
"ellipsoid": {
"ellipsoid_ranges": {"major": 70, "semi_major": 70, "minor": 5},
"rotation": {"dip_azimuth": 0, "dip": 0, "pitch": 0},
},
"max_samples": 40,
"min_samples": 1,
},
"block_discretization": {"nx": 5, "ny": 5, "nz": 5},
"number_of_lines": 500,
"realizations": 10,
"random_seed": 123,
"kriging_method": "simple",
},
},
)
The result looks like this:
{
"target": {
"reference": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/simulation-grid.json",
"name": "simulation-grid",
"simulations": {
"reference": "cell_attributes[?key=='5f4e2c3e-3d3b-4f4a-8e2a-1c2b3d4e5f6a']",
"name": "gold-ppm-simulation"
}
}
}
Apply the same polling pattern to capture this as simulation_result.
To validate and visualize your simulation, use the conditional simulation workflow task. When you set perform_validation to true, it runs the turning-bands simulation together with an inline validation step, producing a validation.json report and a link to the interactive Simulation Validation Dashboard.
Validation needs the full ensemble set — point-scale and block-scale simulations, in both normal-score and original space. The standalone conditional turning bands task saves only the block-scale results, so run the conditional simulation workflow when you want the validation dashboard.
Profit calculation
Finally, classify the blocks as ore or waste with the profit calculation task.
execution_response = requests.post(
"https://{hub}.api.seequent.com/compute/orgs/{org_id}/geostatistics/profit-calculation",
headers={"Authorization": "Bearer {token}"},
allow_redirects=False,
json={
"parameters": {
"source": {
"object": simulation_result["target"]["reference"],
"attribute": simulation_result["target"]["simulations"]["reference"],
},
"target": {
"object": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/simulation-grid.json",
"attribute": {"operation": "create", "name": "gold-classification"},
},
"material_categories": [
{"cutoff_grade": 0.50, "metal_price": 1.0, "label": "waste"},
{"cutoff_grade": 5.00, "metal_price": 3.0, "label": "ore"},
],
"processing_cost": 30.00,
"mining_waste_cost": 20.00,
"mining_ore_cost": 20.00,
"metal_recovery_fraction": 0.4,
},
},
)
The result looks like this:
{
"message": "Profit calculation completed. Groups processed: 8",
"target": {
"reference": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/simulation-grid.json",
"name": "simulation-grid",
"schema_id": "/objects/regular-3d-grid/1.3.0",
"attribute": {
"reference": "cell_attributes[?key=='e200d6df-1b3c-45a4-aa7c-009fe19c00cc']",
"name": "gold-classification"
}
}
}
Now you have a classification of the blocks as ore or waste in the gold-classification attribute of the simulation-grid.json object.