Variography#

import geolime as geo
dh_tom = geo.read_file("../data/dh_tom_comp.geo")

Once the capping value determined, we can create a new property to capp the value above 25.

dh_tom.set_property(name='Zn_cap', data='Zn_pct')
dh_tom.update_property(name='Zn_cap', data='25', region="(Zn_cap > 25)")

Normal Score#

For simplicity in variography analysis, let’s compute the normal scores of the data.

gauss_score function returns a numpy array, so let’s create a new property on the Drillholes.

geo.gauss_score(dh_tom['Zn_cap'])
2025-10-03 14:58:42,263 [WARNING] GeoLime Project - |GEOLIME|.anamorphosis.py : There are NaN in data. They will be ignored.
array([-0.78162595,         nan,         nan, ..., -0.73537037,
       -0.97667753, -1.06409047])
dh_tom.set_property(name="Zn_gauss", data=geo.gauss_score(dh_tom['Zn_cap']))
2025-10-03 14:58:42,308 [WARNING] GeoLime Project - |GEOLIME|.anamorphosis.py : There are NaN in data. They will be ignored.

Experimental Analysis#

Lag Creation#

For Variography analysis, lag creation can be perfom

  • implicitly with a number of lags and a length of lag

  • explicitly with interval values provided.

lags, tol = geo.generate_lags_from_interval([[0, 10], [10, 20], [20, 40]])
lags, tol = geo.generate_lags(lag=40, plag=50, nlags=15)
lags
array([  0.,  40.,  80., 120., 160., 200., 240., 280., 320., 360., 400.,
       440., 480., 520., 560.])
tol
20.0

Variography Analysis is perform in 2 step:

  • finding the main direction

  • computing the semi variogram 1D in the major/semi-major/minor directions

The finding of the main direction is perform through the analysis of variomap is the different planes.

  • Analysis around the Z axis for the azimuth using vario_map / vario_contour;

  • Once found the main azimuth, analysis around the X axis for the dip using vario_contour_dip;

  • Once found the correspond azimuth and dip, analysis around the Z axis for the pitch using vario_contour_pitch

Finding main direction#

geo.vario_map(
    geo_object=dh_tom,
    attribute="Zn_gauss",
    region="Zn_gauss.notna()",
    lags=lags,
    tol=tol,
    n_az=15,
    atol=15,
    backend=geo.GeostatsBackend.RUST,
    rust_multithread=True
)
geo.vario_contour(
    geo_object=dh_tom,
    attribute="Zn_gauss",
    region="Zn_gauss.notna()",
    lags=lags,
    tol=tol,
    n_az=15,
    atol=10,
    user_azimuth=145,
    backend=geo.GeostatsBackend.RUST,
    rust_multithread=True
)
../_images/b6fe9c23634aed8fb15c3b7fa33100c6d787465f1b6847483f9363fcea0bb502.png
geo.vario_contour_dip(
    geo_object=dh_tom,
    attribute="Zn_gauss",
    region="Zn_gauss.notna()",
    lags=lags,
    tol=tol,
    azimuth=145,
    n_dip=18,
    atol=10,
    user_dip=30,
    c_step=None,
    save_file=None,
    backend=geo.GeostatsBackend.RUST,
    rust_multithread=True
)
../_images/5d77f38ac966c3bbb13751b3c34b3b677defbb041d25fdf8d8752f39b3f9fa68.png
lags, tol = geo.generate_lags(lag=5, plag=50, nlags=15)
geo.vario_contour_pitch(
    geo_object=dh_tom,
    attribute="Zn_gauss",
    region="Zn_gauss.notna()",
    lags=lags,
    tol=tol,
    azimuth=145,
    dip=30,
    n_pitch=15,
    atol=10,
    user_pitch=40,
    c_step=None,
    save_file=None,
    backend=geo.GeostatsBackend.RUST,
    rust_multithread=True
)
../_images/b640343e54ce4e5b1532b1083b8b8723f2ba09df5d8cb4db809b62ef04446f4b.png

Computing Major/Semi-major/minor 1D variograms#

lags, tol = geo.generate_lags(lag=40, plag=50, nlags=15)
vario_exp_major = geo.variogram(
    object=dh_tom,
    attribute="Zn_gauss",
    region="Zn_gauss.notna()",
    geographic_azimuth=145,
    dip=30,
    pitch=40,
    lags=lags,
    tol=tol,
    atol=15
)
vario_exp_major
lag npairs avgdist vario
0 0.0 77.0 7.075251 0.465396
1 40.0 3398.0 40.792308 0.777796
2 80.0 40960.0 78.978514 0.806629
3 120.0 30230.0 124.930330 0.990211
4 160.0 40894.0 156.149538 1.115701
5 200.0 36094.0 203.015277 1.081183
6 240.0 25161.0 236.455210 1.035988
7 280.0 33921.0 281.398117 0.942194
8 320.0 37335.0 321.020570 1.038284
9 360.0 25134.0 358.368372 0.778095
10 400.0 26563.0 400.087531 0.820317
11 440.0 23755.0 437.475481 0.803660
12 480.0 16474.0 482.005500 0.954571
13 520.0 15733.0 520.853958 0.870347
14 560.0 15398.0 559.318854 0.754568
geo.plot_semivariogram(
    variograms=[vario_exp_major],
    display_npairs=True
)
vario_exp_semi_major = geo.variogram(
    object=dh_tom,
    attribute="Zn_gauss",
    region="Zn_gauss.notna()",
    geographic_azimuth=145,
    dip=30,
    pitch=-50,
    lags=lags,
    tol=tol,
    atol=15
)

geo.plot_semivariogram(
    variograms=[vario_exp_semi_major],
    display_npairs=True
)
lags, tol = geo.generate_lags(lag=2, plag=50, nlags=15)
vario_exp_minor = geo.variogram(
    object=dh_tom,
    attribute="Zn_gauss",
    region="Zn_gauss.notna()",
    geographic_azimuth=145,
    dip=-60,
    pitch=40,
    lags=lags,
    tol=tol,
    atol=30
)

geo.plot_semivariogram(
    variograms=[vario_exp_minor],
    display_npairs=True
)

Computing Downhole Variogram#

lags, tol = geo.generate_lags(lag=1., plag=50, nlags=20)
vario_exp_bh = geo.variogram_downhole(
    object= dh_tom,
    attribute="Zn_gauss",
    region="Zn_gauss.notna()",
    lags=lags,
    tol=tol,
)
geo.plot_semivariogram(
    variograms=[vario_exp_bh],
    display_npairs=True
)

Automatic Fitting#

Automatic Fitting uses an empty model to fit along experimental variograms. Fitting is usually performed in 2 steps : first fit the nugget and then fit the other structures.

Fitting the Nugget#

nugget_model = geo.Nugget() + geo.Spherical()

The fitting algorithm can be set up to preferrentially fit the small ranges using the INVERSE_DISTANCE or SQUARED_INVERSE_DISTANCE.

geo.model_fit(
    variograms=[vario_exp_bh],
    cov=nugget_model,
    weighting_method=geo.VarioFitWeightingMethod.SQUARED_INVERSE_DISTANCE
)
print(nugget_model)
Model with 2 components 
 
Component 1 : 
Sill : 0.027923352540629543 
Covariance type : Nugget 

Component 2 : 
Sill : 0.6726645994942252 
Covariance type : Spherical 
Scales : (18.850990791545037, 4.749976203702906, 6.537409819166593) 
Angles : (51.99053468369605, 1e-10, 0.0) 

Total sill = 0.7005879520348547 

Model and experimental variogram can be plotted on the same graphic by specifying the parameter model and model_angles. Note that for downhole varigram the model_angles values do not have any importance.

geo.plot_semivariogram(
    variograms=[vario_exp_bh],
    model=nugget_model,
    model_angles=[{"azi":0, "dip":90, "pitch":90}],
    display_npairs=True
)

Each structure component can be accessed using the cov_elem_list attribute.

nugget_model.cov_elem_list[0].sill
0.027923352540629543

Fitting the structures#

model =  geo.Nugget() + geo.Spherical() + geo.Spherical()
short_range_spherical_ratio = 0.6
long_range_spherical_ratio = 0.4
geo.model_fit(
    variograms=[
        vario_exp_major,
        vario_exp_semi_major,
        vario_exp_minor
    ],
    cov=model,
    constraints=[
        {"sill_fixed":0.13},
        {
            "sill_max": short_range_spherical_ratio * (vario_exp_major.attrs["variable_var"] - 0.13),
            "angle_fixed_0": 145,
            "angle_fixed_1": 60,
            "angle_fixed_2": 40,
            "scale_max_0":100,
            "scale_max_1":100,
            "scale_max_2":20 
        },
        {
            "sill_max": long_range_spherical_ratio * (vario_exp_major.attrs["variable_var"] - 0.13),
            "angle_fixed_0": 145,
            "angle_fixed_1": 60,
            "angle_fixed_2": 40, 
        }
    ]
)
geo.plot_semivariogram(
    variograms=[vario_exp_major, vario_exp_semi_major, vario_exp_minor],
    model=model,
    model_angles=[
        {"azi":145, "dip":60, "pitch":40},
        {"azi":145, "dip":60, "pitch":-50},
        {"azi":145, "dip":-30, "pitch":40},
    ],
    display_npairs=True
)
print(model)
Model with 3 components 
 
Component 1 : 
Sill : 0.13 
Covariance type : Nugget 

Component 2 : 
Sill : 0.5420557387062593 
Covariance type : Spherical 
Scales : (3.930152875018527, 85.67720634812147, 9.756860574267415) 
Angles : (145.0, 60.0, 40.0) 

Component 3 : 
Sill : 0.36137049659907544 
Covariance type : Spherical 
Scales : (559.5578867211551, 13.99159101413549, 559.4462269151187) 
Angles : (145.0, 60.0, 40.0) 

Total sill = 1.0334262353053347 
dh_tom.to_file("../data/dh_tom_comp_capped.geo")