How the results are checked
Every method in the app is checked against something outside its own code. The checks are:
- a published value;
- a hand calculation;
- a second, independent way of computing the same number;
- data made with a known answer.
The checks run as automatic tests on every change, so a result that drifts is caught before it is released. The test named in each row below is the one that keeps checking it.
Stereonet and statistics
| What | Checked against | Result | Test |
|---|---|---|---|
| Kamb contours | Vollmer (1995), Computers & Geosciences 21: for 50 readings the expected count is 7.63 and sigma 2.54 | Same to 0.005 | Kamb n=50: expected count 7.63 (Vollmer 1995) |
| Kamb contours | A second program that counts readings one by one with explicit angles | Same at 60 random points to 10⁻⁹ | Kamb: matrix implementation == brute-force angle counting |
| Schmidt (1%) contours | A one-by-one count of the readings inside a 1% circle | Same to 10⁻⁹ | schmidt: the counting circle covers 1% of the net |
| Fisher contours | Theory: averaged over the whole net, the density of any data is exactly 1 | Averages 1 | fisher: the density of ANY data set averages exactly 1 |
| Plotting position and poles | Hand calculation: a plane dipping 55° toward 200° has its pole plunging 35° toward 020° | Exact | known plane: dip 55 toward 200 has its pole plunging 35 toward 020 |
| Mean, Fisher kappa and 95% cone | The first, separately checked version of the maths, run in Posit | Mean pole 53.1° / 199.7°, cone 3.03°, same | cluster: Fisher 95% cone 3.03 deg |
| Principal axes and fold axis | Theory: for a girdle, the smallest axis is the pole to the girdle | Same to 10⁻⁹ | principal axes: for a girdle the minimum axis is the pole to the girdle |
| Intersection of two planes | Hand calculation: planes 30/090 and 40/180 meet at plunge 25.4°, trend 124.5° | Same to 0.001° | plane intersection: planes 30/090 and 40/180 meet at plunge 25.4 trend 124.5 |
| Rotation | Theory: rotating does not change the angles between readings | Spread unchanged | rotation preserves the spread |
| Unfolding | A folded bed made with a known fold | The girdle becomes a tight cluster | noisy fold: unfolding turns a girdle into a tight cluster |
| Rose confidence of the mean | 400 simulated samples with a known mean direction | The 95% wedge holds the true mean about 95% of the time | rose wedge: simulated von Mises samples are covered about 95% of the time |
| Orientation sets | Five data sets made with three known sets plus 10% scatter | 3 sets found every time, axes within 3°, 90% or more of readings in the right set | three sets + 10% scatter: k = 3 recovered on 5 of 5 datasets |
| Orientation sets | Readings spread evenly, with no sets | No sets found | uniformly random orientations: no sets found |
Oriented core (alpha / beta)
| What | Checked against | Result | Test |
|---|---|---|---|
| Alpha / beta to dip and dip direction | Planes of known orientation turned into alpha / beta and back, for 4 hole attitudes × 5 planes × all 16 conventions | Worst error under 0.01° | alpha/beta round trip over |
| The app’s default convention | acQuire’s own stored procedure QSP_STRUCTURE_CALC, on 200 random readings | Same to a millionth of a degree | acQuire procedure: alpha / beta to a plane equals the app's default convention |
| The convention check | Data made with a known convention, in holes drilled four ways | Picks the true convention | convention check: holes in four directions recover the true convention |
| The convention check | Holes that are nearly parallel, which cannot tell conventions apart | Says it cannot decide, rather than guessing | convention check: nearly parallel holes are reported as not decidable |
| The default convention on real data | A mining site’s own calculated dips (729 oriented-core readings; the data are private, so this is not in the automatic tests) | Median difference 0.14°; 92% within 5° | Checked once (tools/convention_vs_reference.R) |
Drillholes
| What | Checked against | Result | Test |
|---|---|---|---|
| Sampling-bias (Terzaghi) correction | Readings drawn from a known 50 / 50 mix of steep and flat planes, as a vertical hole sees them | Weighting restores the 50 / 50 mix | terzaghi: a vertical hole sees few steep planes |
| Fracture frequency and spacing | Structures placed evenly a known distance apart | Known frequency and spacing | frequency: evenly spaced structures give the known frequency |
| RQD from the depths | A worked example by hand (pieces of 0.25, 0.05, 0.40, 0.20, 0.30 and 0.80 m in 2 m) | 97.5% | RQD from depths: a worked example |
| RQD from frequency | Priest and Hudson (1976): 73.6% at 10 fractures a metre | Same to 0.001 | RQD from frequency (Priest and Hudson 1976) |
What has not been checked
- No side-by-side run with Dips, Stereonet 11 or Orient on the same file. The methods are checked against published values and hand calculations, not against those programs’ output.
- The mean, kappa and cone are checked against the first version of the maths (the proof of concept, run separately in Posit). They have not been checked against a published worked example.
- The Bingham confidence ellipse is checked only against that first version.
- The cluster / girdle label uses Woodcock’s K = 1 rule. It is a convention, not a significance test.
- Sets closer together than about twice their spread cannot be told apart. The test above shows two sets 9° apart with a 7° spread found as one.
- Alpha / beta conventions differ between sites. The real-data check above shows the default fits one site’s data. Use the convention check, and a few structures of known orientation, for your own.
The tests are in the project’s tests folder, and they all run before every release.