Example: 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, we'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
We'll need a few objects in our 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.
In this example, we'll use a pointset called composites.json
with one attribute called gold-ppm
. We'll use a variogram model called gold-ppm-variogram.json
, and we'll target a regular-3d-grid called simulation-grid.json
.
Break Ties
Let's start with the break ties task.
execution_response = requests.post(
"https://{hub}.api.seequent.com/compute/orgs/{org_id}/geostat/break-ties",
headers={"Authorization": "Bearer {token}"},
allow_redirects=False,
json={
"parameters": {
"composites": {
"type": "geoscience-object-reference",
"object_reference": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/composites.json",
"object_element": [
{
"type": "element",
"path": "/locations/attributes/@name=gold-ppm",
},
],
},
"target": {
"type": "geoscience-object-reference",
"object_reference": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/composites.json",
"object_element": [
{
"type": "element",
"path": "/locations/attributes/@name=gold-ppm-without-ties",
},
],
},
},
},
)
After starting the task, we 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": "Breaking ties completed.",
"object_modified": {
"type": "geoscience-object-reference",
"object_reference": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/composites.json",
"object_element": [
{
"type": "element",
"path": "/locations/attributes/@name=my-data-without-ties",
},
],
},
}
In the next steps, we won't show the polling code, but you can repeat the same pattern for each task.
Declustering
Next, we'll make declustering weights with the declustering task. The break-ties task gave us a geoscience object reference to the pointset attribute it created, and we can pop that straight into the declustering request.
execution_response = requests.post(
"https://{hub}.api.seequent.com/compute/orgs/{org_id}/geostat/declustering",
headers={"Authorization": "Bearer {token}"},
allow_redirects=False,
json={
"parameters": {
"composites": break_ties_result["object_modified"],
"target": {
"type": "geoscience-object-reference",
"object_reference": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/composites.json",
"object_element": [
{
"type": "element",
"path": "/locations/attributes/@name=gold-ppm-declustering-weights",
},
],
},
"cell_sizes": {
"min_size": 1,
"max_size": 10,
"n_sizes": 3,
"y_anisotropy": 1.0,
"z_anisotropy": 1.0,
"n_offsets": 3,
},
},
},
)
After waiting for the task to finish, the result looks like this:
{
"message": "Declustering completed",
"object_modified": {
"type": "geoscience-object-reference",
"object_reference": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/my-pointset.json",
"object_element": [
{
"type": "element",
"path": "/locations/attributes/@name=gold-ppm-declustering-weights",
},
],
},
}
Continuous Distribution
Now, we'll make a non-parametric continuous cumulative distribution with the continuous distribution task, using our tiebroken data and declustering weights.
execution_response = requests.post(
"https://{hub}.api.seequent.com/compute/orgs/{org_id}/geostat/continuous-distribution",
headers={"Authorization": "Bearer {token}"},
allow_redirects=False,
json={
"parameters": {
"composites": break_ties_result["object_modified"],
"weights": declustering_result["object_modified"],
"target": {
"type": "geoscience-object-reference",
"object_reference": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/gold-ppm-distribution.json",
},
"tail_extrapolations": {
"upper": {
"power_model": {
"power": 1.1,
"min": 0,
},
},
"lower": {
"power_model": {
"power": 1.2,
"max": 99,
},
},
},
"replace": True,
},
},
)
The result looks like this:
{
"message": "Success.",
"object_modified": {
"type": "geoscience-object-reference",
"object_reference": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/gold-ppm-distribution.json",
},
}
Conditional Simulation
Time to simulate! We'll use the conditional simulation task with the tiebroken data and distribution we just made.
This time, let's put the task's parameters into a variable. We'll need them again later.
simulation_parameters = {
"composites": break_ties_result["object_modified"],
"target": {
"type": "geoscience-object-reference",
"object_reference": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/simulation-grid.json",
"object_element": [
{
"type": "element",
"path": "/cell_attributes/@name=gold-ppm-simulation",
},
],
},
"distribution": continuous_distribution_result["object_modified"],
"variogram_model": {
"type": "geoscience-object-reference",
"object_reference": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/gold-ppm-variogram.json",
},
"search_neighborhood": {
"max-samples": 40,
"anisotropy": {
"ellipsoid_ranges": {
"major": 70,
"semi_major": 70,
"minor": 5,
},
"rotation": {
"dip_azimuth": 0,
"dip": 0,
"pitch": 0,
},
},
},
"block_discretization": {
"nx": 1,
"ny": 1,
"nz": 1,
},
"number_of_lines": 500,
"random_seed": 123,
"n_sim": 10,
"kriging_method": "simple",
"variogram_reproduction": True,
"normalize_variogram_model": True,
}
execution_response = requests.post(
"https://{hub}.api.seequent.com/compute/orgs/{org_id}/geostat/conditional-simulation",
headers={"Authorization": "Bearer {token}"},
allow_redirects=False,
json={
"parameters": simulation_parameters,
},
)
The result looks like this:
{
"message": "10 conditional simulations succeeded.",
"target": {
"type": "geoscience-object-reference",
"object_reference": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/simulation-grid.json",
"object_element": [
{
"type": "element",
"path": "/cell_attributes/@name=gold-ppm-simulation",
},
],
},
}
Simulation Report
Now we can make a simulation report to visualize the simulation results.
requests.post(
"https://{hub}.api.seequent.com/compute/orgs/{org_id}/geostat/simulation-report",
headers={"Authorization": "Bearer {token}"},
json={
"parameters": {
"simulation_parameters": simulation_parameters,
"target": "https://{hub}.api.seequent.com/file/v2/orgs/{org_id}/workspaces/{workspace_id}/files/path/gold-ppm-simulation-report.json",
},
},
)
The result looks like this:
{
"message": "Success",
"links": {
"report": "https://{hub}.api.seequent.com/file/v2/orgs/{org_id}/workspaces/{workspace_id}/files/path/gold-ppm-simulation-report.json",
"dashboard": "https://simval.seequent.com/orgs/{org_id}/workspaces/{hub}/{workspace_id}/reports/{report_id}/original",
}
}
The report
link points to a File URL with the report data, and the dashboard
link points to the Simulation Validation Dashboard where you can visualize the simulation results.
Profit Calculation
Finally, we can classify the blocks as ore or waste with the profit calc task.
requests.post(
"https://{hub}.api.seequent.com/compute/orgs/{org_id}/geostat/profit-calc",
headers={"Authorization": "Bearer {token}"},
json={
"parameters": {
"source": simulation_result["object_modified"],
"target": {
"type": "geoscience-object-reference",
"object_reference": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/simulation-grid.json",
"object_element": [
{
"type": "element",
"path": "/cell_attributes/@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": "Calculation completed",
"object_modified": {
"type": "geoscience-object-reference",
"object_reference": "https://{hub}.api.seequent.com/geoscience-object/orgs/{org_id}/workspaces/{workspace_id}/objects/path/simulation-grid.json",
"object_element": [
{
"type": "element",
"path": "/cell_attributes/@name=gold-classification",
},
],
},
}
Finally, we have a classification of the blocks as ore or waste in the gold-classification
attribute of the simulation-grid.json
object.