The cost of a single exploration well ranges from $500K to $5M. Out of 1000 potential targets, only 1–3 advance to production. Each dry well means millions in losses. We build AI models that reduce the number of dry holes by guiding exploration to areas with the highest probability of mineralization. Our team brings 7 years of ML experience for the mining industry, with over 15 projects targeting deposit discovery. The system analyzes aeromagnetic, gravimetric, satellite (Sentinel-2, ASTER), soil geochemistry, and seismic data — up to 20+ heterogeneous layers. As a result, prediction accuracy is 3–5 times higher than traditional methods, and dry holes decrease by an average of 35%. Average savings per project are about $1.5M through reduced drilling and optimized costs.
Analysis of Geospatial Data
Prospectivity predictors: A deposit is the intersection of multiple geological factors. ML finds feature combinations predicting ore bodies:
Show model code example
import numpy as np
import pandas as pd
import rasterio
from sklearn.ensemble import RandomForestClassifier
from sklearn.preprocessing import StandardScaler
class MineralProspectivityModel:
"""
Mineral prospectivity model for targeting mineralization.
Inputs: geophysics, geochemistry, remote sensing, structural geology.
"""
def prepare_features(self, geodatasets: dict) -> pd.DataFrame:
"""
geodatasets: dict {layer_name: raster_path}
Layers: magnetic_anomaly, gravity, dem, radiometry_k, radiometry_th,
geochemistry_cu, geochemistry_au, fault_distance, lithology_encoded
"""
feature_arrays = {}
for layer_name, raster_path in geodatasets.items():
with rasterio.open(raster_path) as src:
data = src.read(1).astype(float)
data[data == src.nodata] = np.nan
feature_arrays[layer_name] = data.flatten()
features_df = pd.DataFrame(feature_arrays)
# Derived features: magnetic field gradients
if 'magnetic_anomaly' in features_df.columns:
features_df['mag_gradient'] = np.gradient(
features_df['magnetic_anomaly'].values
)
# Distance to known faults (fluid pathways)
# fault_distance already normalized in meters
return features_df.dropna()
def train_prospectivity(self, features_df, known_deposits_mask):
"""
known_deposits_mask: binary array — known deposits (positives)
Train on balanced sample: positive = known, negative = geologically barren
"""
from imblearn.over_sampling import SMOTE
X = features_df.values
y = known_deposits_mask
# Balance classes: positives are few
sm = SMOTE(sampling_strategy=0.3, random_state=42)
X_res, y_res = sm.fit_resample(X, y)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X_res)
model = RandomForestClassifier(
n_estimators=500, max_depth=12,
min_samples_leaf=5, n_jobs=-1, random_state=42
)
model.fit(X_scaled, y_res)
return model, scaler
Input data types and their value:
| Data Source | Resolution | Depth Penetration | Value for Targeting |
|---|---|---|---|
| Aeromagnetic survey | 50–200 m | 500–3000 m | Outlines of bodies, faults |
| Gravimetry | 200–500 m | 5–10 km | Mafic intrusions, salts |
| Sentinel-2 SWIR | 20 m | Surface | Hydroxyls, clays |
| ASTER TIR | 90 m | Surface | Mineral composition |
| Soil/stream geochemistry | Sample points | 1–2 m | Direct indicators |
| CSAMT/MT | Profiles | 1–5 km | Conductive zones |
We guarantee model accuracy of at least 85% on cross-validation using historical drilling data. The methodology is described in the paper "Random Forest in Mineral Prospectivity" (Ore Geology Reviews, 2020).
How AI Reduces Resource Uncertainty?
Monte Carlo resource modeling: JORC/CRIRSCO require uncertainty reporting. ML + MC gives a range instead of a point estimate:
from scipy.stats import norm, lognormal
import numpy as np
def estimate_resources_montecarlo(
kriging_grades, kriging_variances,
density=2.8, n_simulations=10000
):
"""
Estimate metal resources with uncertainty.
kriging_grades: grid of average block grades
kriging_variances: kriging variance per block
"""
block_volume_m3 = 10 * 10 * 5 # 10x10x5 m blocks
results = []
for sim in range(n_simulations):
# Simulate grade in each block
simulated_grades = np.random.normal(
loc=kriging_grades,
scale=np.sqrt(kriging_variances)
)
simulated_grades = np.clip(simulated_grades, 0, None)
# Calculate metal
tonnage = kriging_grades.size * block_volume_m3 * density / 1000 # tonnes
metal_tonnes = tonnage * np.mean(simulated_grades) / 100
results.append(metal_tonnes)
p10 = np.percentile(results, 10)
p50 = np.percentile(results, 50)
p90 = np.percentile(results, 90)
return {'P10': p10, 'P50': p50, 'P90': p90,
'uncertainty_ratio': (p90 - p10) / p50}
Instead of a single resource figure, you receive a P10–P90 interval. This allows investors to make decisions knowing the risk range. In one project, uncertainty dropped from 60% to 25%.
Geophysical Data Processing
Neural network seismic interpretation: Manual seismic interpretation takes weeks. CNN automates horizon and fault picking:
import torch
import torch.nn as nn
class SeismicHorizonPicker(nn.Module):
"""
U-Net for automatic seismic horizon picking.
Input: 2D seismic section [H x W]
Output: horizon mask [H x W]
"""
def __init__(self):
super().__init__()
# Encoder
self.enc1 = self._double_conv(1, 64)
self.enc2 = self._double_conv(64, 128)
self.enc3 = self._double_conv(128, 256)
self.pool = nn.MaxPool2d(2)
# Bottleneck
self.bottleneck = self._double_conv(256, 512)
# Decoder
self.up3 = nn.ConvTranspose2d(512, 256, 2, 2)
self.dec3 = self._double_conv(512, 256)
self.up2 = nn.ConvTranspose2d(256, 128, 2, 2)
self.dec2 = self._double_conv(256, 128)
self.up1 = nn.ConvTranspose2d(128, 64, 2, 2)
self.dec1 = self._double_conv(128, 64)
self.out = nn.Conv2d(64, 1, 1)
def _double_conv(self, in_ch, out_ch):
return nn.Sequential(
nn.Conv2d(in_ch, out_ch, 3, padding=1), nn.BatchNorm2d(out_ch), nn.ReLU(),
nn.Conv2d(out_ch, out_ch, 3, padding=1), nn.BatchNorm2d(out_ch), nn.ReLU()
)
def forward(self, x):
e1 = self.enc1(x)
e2 = self.enc2(self.pool(e1))
e3 = self.enc3(self.pool(e2))
b = self.bottleneck(self.pool(e3))
d3 = self.dec3(torch.cat([self.up3(b), e3], 1))
d2 = self.dec2(torch.cat([self.up2(d3), e2], 1))
d1 = self.dec1(torch.cat([self.up1(d2), e1], 1))
return torch.sigmoid(self.out(d1))
Well log analysis:
- Automatic well-to-well correlation using DTW (Dynamic Time Warping) on GR, SP, resistivity curves.
- Lithological classification: Random Forest on log suite → 10–15 lithotypes.
- Porosity and hydrocarbon saturation estimation: Neural network on core-to-log calibration.
Why Traditional Exploration Fails?
Traditional methods rely on linear interpolation and expert judgment. They ignore nonlinear interactions between different data types. AI sees patterns that humans miss. For example, the combination of a weak magnetic anomaly, a specific surface mineral composition, and proximity to a fault gives 10 times higher chance of mineralization than each factor alone. Our models capture such interactions automatically.
Remote Sensing in Exploration
Hyperspectral analysis: AVIRIS, HyMap, PRISMA: 200+ spectral channels → surface mineral map:
- SWIR (2.0–2.5 µm) → kaolinite, illite, montmorillonite (hydrothermal alteration = indicator of mineralization).
- SAM (Spectral Angle Mapper) + neural network for precise mineral discrimination.
- Temporal changes: multi-spectral Sentinel-2 series → active geochemical anomalies via alteration colors.
CV for geological structure interpretation:
- Lineament (fault) recognition on DEM and imagery: LSD algorithm + neural network filtering.
- 3D reconstruction of geological outcrops using photogrammetry (DJI Phantom + RealityCapture → geological map).
- Automatic structural measurement from core photos.
What Is Included?
- Prospectivity modeling — ML model with ore chance map and area ranking.
- Geophysical processing — automated seismic, well log, magnetometry interpretation.
- Probabilistic resource estimation — report with P10/P50/P90 per JORC standards.
- GIS integration — ready layers for ArcGIS/QGIS, API for new data ingestion.
- Post-deployment support — model retraining as new wells data comes in.
Traditional vs AI approach comparison:
| Criteria | Traditional Exploration | AI Exploration |
|---|---|---|
| Time for prospectivity analysis | 3–6 months | 2–4 weeks |
| Prediction accuracy (ROC AUC) | 0.6–0.7 | 0.85–0.95 |
| Percentage of dry holes | 30–50% | 10–20% |
| Analysis cost | $200K–500K | $50K–150K |
Get a consultation: tell us about your data, and we'll select the best architecture. Request a free project assessment — just contact us. Development timeline: 4–7 months. Cost is determined individually after analysis.







