Metadata-Version: 2.4
Name: blastfrag
Version: 0.2.2
Summary: Blast-fragmentation prediction from a bench pattern: the published ladder from Kuz-Ram to stacking ensembles, scored on real measured blasts under three split protocols, with the statistic named (variance explained, not squared correlation).
Author: Felipe Santibanez-Leal
License: MIT
Project-URL: Homepage, https://github.com/fsantibanezleal/CAOS_BlastFrag
Project-URL: Documentation, https://github.com/fsantibanezleal/CAOS_BlastFrag/blob/main/docs/README.md
Project-URL: Issues, https://github.com/fsantibanezleal/CAOS_BlastFrag/issues
Project-URL: Changelog, https://github.com/fsantibanezleal/CAOS_BlastFrag/blob/main/CHANGELOG.md
Keywords: blasting,drill and blast,rock fragmentation,fragment size distribution,kuz-ram,kuznetsov,rosin-rammler,swebrec,crush zone model,mining,open pit,muckpile,mine to mill,comminution,rock factor,blastability index,in situ block size
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Physics
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.24
Provides-Extra: learned
Requires-Dist: scikit-learn>=1.3; extra == "learned"
Provides-Extra: boost
Requires-Dist: xgboost>=2.0; extra == "boost"
Provides-Extra: export
Requires-Dist: onnx>=1.15; extra == "export"
Requires-Dist: skl2onnx>=1.16; extra == "export"
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: ruff>=0.6; extra == "dev"
Requires-Dist: build>=1.0; extra == "dev"
Requires-Dist: scikit-learn>=1.3; extra == "dev"
Requires-Dist: xgboost>=2.0; extra == "dev"
Dynamic: license-file

# blastfrag

[![CI](https://github.com/fsantibanezleal/CAOS_BlastFrag/actions/workflows/ci.yml/badge.svg)](https://github.com/fsantibanezleal/CAOS_BlastFrag/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)

Blast-fragmentation prediction from a bench pattern. The published ladder from the 1973 classical
mean-size equation to the 2025 stacking ensemble, scored on real measured blasts under three split
protocols, with the statistic named (variance explained, not squared correlation).

```bash
pip install blastfrag
```

## Why this exists

Predicting the mean fragment size of a muckpile from a drill-and-blast design is a solved-looking
problem with a large literature and one widely used model. Working through that literature against
the data it is fitted on turns up things a formula collection would hide.

**The classical model barely beats a constant.** On the published twelve-blast hold-out it explains
0.232 of the variance about the identity line, and its root-mean-square error of 0.1279 m improves on
simply predicting the training mean by 13 percent. The figure usually quoted for it, 0.57, is a
squared correlation, which is a different quantity: a model can correlate at 0.755 and still be badly
biased, and this one is.

**The corpus is dimensionless, so the classical model could not run on it at all.** It needs rock
volume and charge mass per hole and the published table has only ratios. The source's own prose gives
a hole diameter for eight of its ten sites, which closes the system, and the reconstruction is
asserted against fifteen dimensional constraints the same prose states.

**The rock factors both source papers say they estimated were never printed.** Back-solving them from
the published predictions recovers values that are near constant within each site and ordered by rock
stiffness.

## What it does

```python
import blastfrag as bf

train = bf.load_training_corpus()          # 97 real bench blasts, ten sites
holdout = bf.load_holdout(protocol="2012") # the published validation set, leakage flagged

pattern = bf.reconstruct_pattern(train[0])
pattern.rock_volume_m3, pattern.charge_mass_kg
```

Loading the training corpus runs a two-part integrity gate. The first part reproduces the source
paper's own descriptive statistics from the shipped rows; the second compares a content digest
against a pinned value. The first says the file still is the published table, the second says it has
not moved since it was corrected.

That gate found five transcription defects in the corpus as it was first assembled, two of them on
the regression target.

## Refusing rather than guessing

A model that needs a rock volume cannot run on a site whose scale is unpublished. One of the ten
sites is in exactly that position, and its six rows are the geometry negative control:

```python
miami = [b for b in train if b.site == "Miami"][0]
bf.reconstruct_pattern(miami)   # raises GeometryUnavailable, with the reason
```

Abstention is a first-class result throughout: a `Prediction` carries either a value or a reason, and
never a number that was filled in to avoid a hole.

## Naming the statistic

Two different quantities are called `R2` in this literature and they differ by a factor of two and a
half on the same twelve blasts. Every figure this package returns carries the name of what it is, and
a null model that predicts the training mean runs beside every other arm.

## Datasets

| Set | Rows | Source |
|---|---|---|
| training corpus | 97 | Hudaverdi, Kulatilake and Kuzu 2010, `doi:10.1002/nag.957`, Tables I and II |
| published hold-out | 14 | the union of the 2010 Table VIII and the 2012 Tables 4 and 5, `doi:10.1007/s10706-012-9496-3` |
| field hold-out | 5 | Sui, Zhou, Zhao, Yang and Zou 2025, `doi:10.3390/app15031254`, CC BY 4.0 |

Numeric values are experimental facts reused with citation. The source PDFs are not redistributed.

The field hold-out is an extrapolation by construction: its Young modulus of 5.6 GPa sits below the
corpus minimum of 9.57 GPa, on the feature two independent 2025 studies both rank most important.
Predictions on it are stamped.

## Documentation

The [`docs/`](docs/README.md) wiki carries the theory, every equation term by term with its source,
the data contract, and the reasoning behind each modelling choice.

## Scope

No mechanistic simulation: there is no discrete-element or hybrid stress blasting model here, and a
hand-rolled approximation under those names would be worse than nothing. No non-ideal detonics. No
flyrock and no ground vibration. Model constants that no primary source prints, including the timing
factor of the modified classical model and the crush-zone branch parameters, are exposed as
user-supplied values with documented ranges rather than invented.

## Licence

MIT. See [LICENSE](LICENSE).
