├── .gitignore ├── LICENSE ├── README.md ├── examples ├── IDW2D.py ├── IDW3D.py ├── OK2D.py ├── OK2DWithNestVariogram.py ├── OK3D.py ├── OK3DWithNestVariogram.py ├── SK2D.py ├── SK2DWithNestVariogram.py ├── SK3D.py ├── SK3DWithNestVariogram.py ├── __init__.py ├── data │ ├── AustraliaTemperature20210101.csv │ ├── sample_data.gslib │ └── tatitlek_815_mhhw_2011.nc ├── gui │ └── guiDemo.py ├── ncFileUtil.py ├── nestVariogram.py ├── plotUtils.py ├── temperature.py ├── tf │ ├── IDW2D.py │ ├── IDW3D.py │ ├── OK2D.py │ ├── OK2DWithNestVariogram.py │ ├── OK3D.py │ ├── OK3DWithNestVariogram.py │ ├── SK2D.py │ ├── SK2DWithNestVariogram.py │ ├── SK3D.py │ └── SK3DWithNestVariogram.py └── variogram.py ├── figs └── OK3D.jpg ├── requirements.txt └── src └── tfinterpy ├── __init__.py ├── grid.py ├── gslib ├── __init__.py └── fileUtils.py ├── gui ├── __init__.py ├── canvas.py ├── tool.py ├── tool.ui └── uiTool.py ├── idw.py ├── krige.py ├── tf ├── __init__.py ├── commonLayer.py ├── idw.py ├── krige.py └── variogramLayer.py ├── utils.py ├── variogram.py ├── variogramExp.py ├── variogramModel.py └── vtk ├── __init__.py ├── colorMap.py ├── fileUtils.py └── rendering.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | __pycache__/ 3 | .idea/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## TFInterpy 2 | TFInterpy is a Python package for spatial interpolation. A high-performance version of several interpolation algorithms is implemented based on TensorFlow. Including parallelizable IDW and Kriging algorithms. So far, tfinterpy is the **fastest open source Kriging** algorithm, which can reduce the operation time of large-scale interpolation tasks by an order of magnitude 3 | 4 | ## Link to our paper 5 | [TFInterpy: A high-performance spatial interpolation Python package](https://www.sciencedirect.com/science/article/pii/S2352711022001479) 6 |
7 | (https://doi.org/10.1016/j.softx.2022.101229) 8 | 9 | ### Performance comparison (unit: second) 10 | 11 | | Grid size | GeostatsPy-OK | PyKrige-OK | TFInterpy-OK | TFInterpy-TFOK(GPU) | TFInterpy-TFOK(CPU) | 12 | | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | 13 | | 1x104 | 23.977 | 1.258 | 0.828 | 2.070 | 0.979 | 14 | | 1x105 | 230.299 | 12.264 | 8.140 | 6.239 | 2.067 | 15 | | 1x106 | 2011.351 | 121.711 | 82.397 | 45.737 | 11.683 | 16 | | 1x107 | 2784.843 | 1250.980 | 849.974 | 452.567 | 112.331 | 17 | 18 | ### Screenshots 19 | Snapshot of GUI tool. 20 | ![Snapshot of GUI tool](./figs/OK3D.jpg) 21 | 22 | #### Requirements 23 | 24 | **Minimum usage requirements:** Python 3+, Numpy, SciPy 25 | 26 | **TensorFlow based algorithm:** TensorFlow 2 27 | 28 | **GSLIB file support:** Pandas 29 | 30 | **3D visualization:** VTK 31 | 32 | **GUI Tool:** PyQT5 33 | 34 | ----- 35 | 36 | # Usage 37 | 38 | #### Install tfinterpy 39 | ``` 40 | pip install tfinterpy 41 | ``` 42 | 43 | #### Then install dependencies 44 | 45 | **Full dependencies** : (To avoid package version issues, the specific version numbers tested in Python3.9 are listed here) 46 | ``` 47 | pip install matplotlib==3.9.4 48 | pip install numpy==2.0.2 49 | pip install pandas==2.2.3 50 | pip install PyQt5==5.15.11 51 | pip install scipy==1.13.1 52 | pip install tensorflow==2.18.0 53 | pip install vtk==9.4.1 54 | ``` 55 | 56 | **Notice!** You may do not need to install all dependencies 57 | - If you only need to use the most basic interpolation algorithm, install the following package. (see "examples/" for usage) 58 | ``` 59 | pip install numpy==2.0.2 60 | pip install scipy==1.13.1 61 | ``` 62 | - If you need to use TensorFlow-based interpolation algorithms, you need to install tensorflow. (see "examples/tf" for usage) 63 | ``` 64 | pip install tensorflow==2.18.0 65 | ``` 66 | or (Use GPU for computing) 67 | ``` 68 | pip install tensorflow-gpu==2.18.0 69 | ``` 70 | - If you need to use the built-in GUI tools (see "examples/gui" for usage) provided, please install full dependencies as above list. 71 | 72 | ### Run examples 73 | 74 | All of the sample code can be found in the "examples" folder, the examples directory is recommended as the working directory. 75 | 76 | netCDF4 needs to be installed first to load the data. 77 | ``` 78 | pip install netCDF4==1.7.2 79 | ``` 80 | 81 | 82 | -------------------------------------------------------------------------------- /examples/IDW2D.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.idw import IDW 2 | from tfinterpy.grid import Grid2D 3 | from ncFileUtil import getSamples 4 | from plotUtils import * 5 | import numpy as np 6 | import random 7 | 8 | if __name__ == "__main__": 9 | random.seed(1) 10 | W, H = 100, 100 11 | M = 100 12 | offset = (400, 800) 13 | N = 8 14 | 15 | # Get sample points and original elevation data from netcdf file 16 | # containing Digital Elevation Model data. 17 | samples, lats, lons, ele = getSamples("data/tatitlek_815_mhhw_2011.nc", 'lat', 'lon', 'Band1', 18 | offset, (W, H), M) 19 | # Create linear 2D grid. 20 | grid = Grid2D() 21 | grid.rectlinear((W, H), (1, W), (1, H)) 22 | 23 | exe = IDW(samples)# Create a idw interpolator. 24 | grid.pro = exe.execute(grid.points(), N)# Perform interpolation of all points in the grid. 25 | 26 | print(exe.crossValidate(N))# Perform leave-one-out validation and print result. 27 | print(exe.crossValidateKFold(10, N))# Perform k-fold validation and print result. 28 | 29 | pro = grid.pro.reshape((grid.dim[1], grid.dim[0]))# Reshape properties as 2d ndarray. 30 | plt.figure() 31 | plt.subplot(221) 32 | img2d(ele, title="Origin")# Plotting original elevation data. 33 | plt.subplot(222) 34 | img2d(pro, title="IDW")# Plotting interpolation results. 35 | absdiff = np.abs(pro - ele) 36 | plt.subplot(223) 37 | img2d(absdiff, title="AE")# Plotting absolute errors. 38 | print('result MAE:', np.mean(absdiff)) 39 | plt.show() 40 | -------------------------------------------------------------------------------- /examples/IDW3D.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.idw import IDW 2 | from tfinterpy.grid import Grid3D 3 | from tfinterpy.gslib.fileUtils import readGslibPoints 4 | import tfinterpy.vtk.colorMap as CM 5 | from tfinterpy.vtk.rendering import createGridActor, rendering 6 | from tfinterpy.vtk.fileUtils import saveVTKGrid 7 | 8 | if __name__ == "__main__": 9 | filePath = "data/sample_data.gslib" 10 | N = 8 11 | df = readGslibPoints(filePath)# Read 3d points from gslib file. 12 | print(df.describe()) 13 | samples = df[['x', 'y', 'z', 'porosity']].values 14 | 15 | # Create linear 3D grid. 16 | grid = Grid3D() 17 | grid.rectlinear((100, 100, 10), (samples[:, 0].min(), samples[:, 0].max()), 18 | (samples[:, 1].min(), samples[:, 1].max()), (samples[:, 2].min(), samples[:, 2].max())) 19 | exe = IDW(samples, '3d')# Create a idw interpolator. 20 | 21 | grid.pro = exe.execute(grid.points(), N)# Perform interpolation of all points in the grid. 22 | print(exe.crossValidate(N))# Perform leave-one-out validation and print result. 23 | print(exe.crossValidateKFold(10, N))# Perform k-fold validation and print result. 24 | 25 | # Create an actor representing a rectilinear grid and use the interpolation results for color mapping. 26 | actor = createGridActor(*grid.dim, grid.x, grid.y, grid.z, grid.pro, 27 | [samples[:, 3].min(), samples[:, 3].max()], CM.Rainbow) 28 | rendering(actor)# Rendering vtkActor. 29 | saveVTKGrid('savedData/grid.vtk', actor.GetMapper().GetInput())# Save grid data to vtk file. 30 | -------------------------------------------------------------------------------- /examples/OK2D.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.krige import OK 2 | from tfinterpy.grid import Grid2D 3 | from ncFileUtil import getSamples 4 | from plotUtils import * 5 | from tfinterpy.variogram import calculateDefaultVariogram2D 6 | import numpy as np 7 | import random 8 | 9 | if __name__ == "__main__": 10 | random.seed(1) 11 | filePath = "data/tatitlek_815_mhhw_2011.nc" 12 | W, H = 50, 100 13 | M = 80 14 | offset = (400, 800) 15 | N = 8 16 | 17 | # Get sample points and original elevation data from netcdf file 18 | # containing Digital Elevation Model data. 19 | samples, lats, lons, ele = getSamples(filePath, 'lat', 'lon', 'Band1', offset, (W, H), M) 20 | 21 | # Create linear 2D grid. 22 | grid = Grid2D() 23 | grid.rectlinear((W, H), (1, W), (1, H)) 24 | 25 | # Calculate a default variogram function. 26 | vb = calculateDefaultVariogram2D(samples) 27 | exe = OK(samples)# Create a ok interpolator. 28 | # Perform interpolation of all points in the grid. 29 | grid.pro, grid.sigma = exe.execute(grid.points(), N, vb.getVariogram()) 30 | 31 | print(exe.crossValidate(N, vb.getVariogram()))# Perform leave-one-out validation and print result. 32 | print(exe.crossValidateKFold(10, N, vb.getVariogram()))# Perform k-fold validation and print result. 33 | 34 | grid.pro.resize((grid.dim[1], grid.dim[0]))# Reshape properties as 2d ndarray. 35 | grid.sigma.resize((grid.dim[1], grid.dim[0]))# Reshape kriging variances as 2d ndarray. 36 | ae = np.abs(grid.pro - ele) 37 | print("mae:", np.mean(ae)) 38 | plt.subplot(221) 39 | img2d(ele, title="origin")# Plotting original elevation data. 40 | plt.subplot(222) 41 | img2d(grid.pro, title="estimate")# Plotting interpolation results. 42 | plt.subplot(223) 43 | img2d(ae, title="error")# Plotting absolute errors. 44 | plt.subplot(224) 45 | img2d(grid.sigma, title="krige variance")# Plotting kriging variances. 46 | plt.show() 47 | -------------------------------------------------------------------------------- /examples/OK2DWithNestVariogram.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.krige import OK 2 | from tfinterpy.grid import Grid2D 3 | from ncFileUtil import getSamples 4 | from plotUtils import * 5 | from tfinterpy.variogram import calculateOmnidirectionalVariogram2D 6 | from tfinterpy.utils import calcVecs 7 | import numpy as np 8 | import random 9 | 10 | if __name__ == "__main__": 11 | random.seed(1) 12 | filePath = "data/tatitlek_815_mhhw_2011.nc" 13 | W, H = 100, 100 14 | M = 100 15 | offset = (400, 800) 16 | N = 8 17 | 18 | # Get sample points and original elevation data from netcdf file 19 | # containing Digital Elevation Model data. 20 | samples, lats, lons, ele = getSamples(filePath, 'lat', 'lon', 'Band1', offset, (W, H), M) 21 | 22 | # Create linear 2D grid. 23 | grid = Grid2D() 24 | grid.rectlinear((W, H), (1, W), (1, H)) 25 | 26 | # Calculate a nested variogram function. 27 | nv, vbs = calculateOmnidirectionalVariogram2D(samples, model=None) 28 | for vb in vbs: 29 | plt.figure() 30 | vb.showVariogram() 31 | plt.show() 32 | 33 | exe = OK(samples)# Create a ok interpolator. 34 | # Perform interpolation of all points in the grid. 35 | grid.pro, grid.sigma = exe.execute(grid.points(), N, nv) 36 | 37 | print(exe.crossValidate(N, nv))# Perform leave-one-out validation and print result. 38 | print(exe.crossValidateKFold(10, N, nv))# Perform k-fold validation and print result. 39 | 40 | grid.pro.resize((grid.dim[1], grid.dim[0]))# Reshape properties as 2d ndarray. 41 | grid.sigma.resize((grid.dim[1], grid.dim[0]))# Reshape kriging variances as 2d ndarray. 42 | 43 | ae = np.abs(grid.pro - ele) 44 | print("mae:", np.mean(ae)) 45 | plt.subplot(221) 46 | img2d(ele, title="origin")# Plotting original elevation data. 47 | plt.subplot(222) 48 | img2d(grid.pro, title="estimate")# Plotting interpolation results. 49 | plt.subplot(223) 50 | img2d(ae, title="error")# Plotting absolute errors. 51 | plt.subplot(224) 52 | img2d(grid.sigma, title="krige variance")# Plotting kriging variances. 53 | plt.show() 54 | -------------------------------------------------------------------------------- /examples/OK3D.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.krige import OK 2 | from tfinterpy.grid import Grid3D 3 | from tfinterpy.variogram import calculateDefaultVariogram3D 4 | from tfinterpy.gslib.fileUtils import readGslibPoints 5 | import tfinterpy.vtk.colorMap as CM 6 | from tfinterpy.vtk.rendering import createGridActor, rendering 7 | from tfinterpy.vtk.fileUtils import saveVTKGrid 8 | import matplotlib.pyplot as plt 9 | 10 | if __name__ == "__main__": 11 | filePath = "data/sample_data.gslib" 12 | N = 8 13 | df = readGslibPoints(filePath)# Read 3d points from gslib file. 14 | print(df.describe()) 15 | samples = df[['x', 'y', 'z', 'porosity']].values 16 | 17 | # Create linear 3D grid. 18 | grid = Grid3D() 19 | grid.rectlinear((100, 100, 10), (samples[:, 0].min(), samples[:, 0].max()), 20 | (samples[:, 1].min(), samples[:, 1].max()), (samples[:, 2].min(), samples[:, 2].max())) 21 | exe = OK(samples, '3d')# Create a ok interpolator. 22 | 23 | vb = calculateDefaultVariogram3D(samples)# Calculate a default variogram function. 24 | plt.figure() 25 | vb.showVariogram() 26 | plt.show() 27 | 28 | # Perform interpolation of all points in the grid. 29 | grid.pro, grid.sigma = exe.execute(grid.points(), N, vb.getVariogram()) 30 | print(exe.crossValidate(N, vb.getVariogram()))# Perform leave-one-out validation and print result. 31 | print(exe.crossValidateKFold(10, N, vb.getVariogram()))# Perform k-fold validation and print result. 32 | 33 | # Create an actor representing a rectilinear grid and use the interpolation results for color mapping. 34 | actor = createGridActor(*grid.dim, grid.x, grid.y, grid.z, grid.pro, 35 | [samples[:, 3].min(), samples[:, 3].max()], CM.Rainbow) 36 | rendering(actor)# Rendering vtkActor. 37 | # Create an actor representing a rectilinear grid and use the kriging variances for color mapping. 38 | actor = createGridActor(*grid.dim, grid.x, grid.y, grid.z, grid.sigma, None, CM.Rainbow) 39 | rendering(actor)# Rendering vtkActor. 40 | saveVTKGrid('savedData/grid.vtk', actor.GetMapper().GetInput())# Save grid data(kriging variances) to vtk file. 41 | -------------------------------------------------------------------------------- /examples/OK3DWithNestVariogram.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.krige import OK 2 | from tfinterpy.grid import Grid3D 3 | from tfinterpy.variogram import calculateOmnidirectionalVariogram3D 4 | from tfinterpy.gslib.fileUtils import readGslibPoints 5 | from tfinterpy.vtk.rendering import createGridActor, rendering 6 | import tfinterpy.vtk.colorMap as CM 7 | from tfinterpy.vtk.fileUtils import saveVTKGrid 8 | from tfinterpy.utils import calcVecs 9 | import matplotlib.pyplot as plt 10 | 11 | if __name__ == "__main__": 12 | filePath = "data/sample_data.gslib" 13 | N = 8 14 | df = readGslibPoints(filePath)# Read 3d points from gslib file. 15 | print(df.describe()) 16 | samples = df[['x', 'y', 'z', 'porosity']].values 17 | 18 | # Create linear 3D grid. 19 | grid = Grid3D() 20 | grid.rectlinear((100, 100, 10), (samples[:, 0].min(), samples[:, 0].max()), 21 | (samples[:, 1].min(), samples[:, 1].max()), (samples[:, 2].min(), samples[:, 2].max())) 22 | 23 | # Calculate a nested variogram function. 24 | nestVariogram, variogramBuilders = calculateOmnidirectionalVariogram3D(samples) 25 | for vb in variogramBuilders: 26 | plt.figure() 27 | vb.showVariogram() 28 | plt.show() 29 | 30 | exe = OK(samples, '3d')# Create a ok interpolator. 31 | # Perform interpolation of all points in the grid. 32 | grid.pro, grid.sigma = exe.execute(grid.points(), N, nestVariogram) 33 | 34 | print(exe.crossValidate(N, nestVariogram))# Perform leave-one-out validation and print result. 35 | print(exe.crossValidateKFold(10, N, nestVariogram))# Perform k-fold validation and print result. 36 | # Create an actor representing a rectilinear grid and use the interpolation results for color mapping. 37 | actor = createGridActor(*grid.dim, grid.x, grid.y, grid.z, grid.pro, 38 | [samples[:, 3].min(), samples[:, 3].max()], CM.Rainbow) 39 | rendering(actor)# Rendering vtkActor. 40 | # Create an actor representing a rectilinear grid and use the kriging variances for color mapping. 41 | actor = createGridActor(*grid.dim, grid.x, grid.y, grid.z, grid.sigma, None, CM.Rainbow) 42 | rendering(actor)# Rendering vtkActor. 43 | saveVTKGrid('savedData/grid.vtk', actor.GetMapper().GetInput())# Save grid data(kriging variances) to vtk file. 44 | -------------------------------------------------------------------------------- /examples/SK2D.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.krige import SK 2 | from tfinterpy.grid import Grid2D 3 | from tfinterpy.variogram import calculateDefaultVariogram2D 4 | from ncFileUtil import getSamples 5 | from plotUtils import * 6 | import numpy as np 7 | import random 8 | 9 | if __name__ == "__main__": 10 | random.seed(1) 11 | filePath = "data/tatitlek_815_mhhw_2011.nc" 12 | W, H = 100, 100 13 | M = 100 14 | offset = (400, 800) 15 | N = 8 16 | 17 | # Get sample points and original elevation data from netcdf file 18 | # containing Digital Elevation Model data. 19 | samples, lats, lons, ele = getSamples(filePath, 'lat', 'lon', 'Band1', offset, (W, H), M) 20 | 21 | # Create linear 2D grid. 22 | grid = Grid2D() 23 | grid.rectlinear((W, H), (1, W), (1, H)) 24 | 25 | # Calculate a default variogram function. 26 | vb = calculateDefaultVariogram2D(samples) 27 | exe = SK(samples)# Create a sk interpolator. 28 | # Perform interpolation of all points in the grid. 29 | grid.pro, grid.sigma = exe.execute(grid.points(), N, vb.getVariogram()) 30 | 31 | print(exe.crossValidate(N, vb.getVariogram()))# Perform leave-one-out validation and print result. 32 | print(exe.crossValidateKFold(10, N, vb.getVariogram()))# Perform k-fold validation and print result. 33 | 34 | grid.pro.resize((grid.dim[1], grid.dim[0]))# Reshape properties as 2d ndarray. 35 | grid.sigma.resize((grid.dim[1], grid.dim[0]))# Reshape kriging variances as 2d ndarray. 36 | ae = np.abs(grid.pro - ele) 37 | print("mae:", np.mean(ae)) 38 | plt.subplot(221) 39 | img2d(ele, title="origin")# Plotting original elevation data. 40 | plt.subplot(222) 41 | img2d(grid.pro, title="estimate")# Plotting interpolation results. 42 | plt.subplot(223) 43 | img2d(ae, title="error")# Plotting absolute errors. 44 | plt.subplot(224) 45 | img2d(grid.sigma, title="krige variance")# Plotting kriging variances. 46 | plt.show() 47 | -------------------------------------------------------------------------------- /examples/SK2DWithNestVariogram.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.krige import SK 2 | from tfinterpy.grid import Grid2D 3 | from tfinterpy.variogram import calculateDefaultVariogram2D, calculateOmnidirectionalVariogram2D 4 | from tfinterpy.utils import calcVecs 5 | from ncFileUtil import getSamples 6 | from plotUtils import * 7 | import numpy as np 8 | import time 9 | 10 | if __name__ == "__main__": 11 | filePath = "data/tatitlek_815_mhhw_2011.nc" 12 | W, H = 100, 100 13 | M = 100 14 | offset = (400, 800) 15 | N = 8 16 | 17 | # Get sample points and original elevation data from netcdf file 18 | # containing Digital Elevation Model data. 19 | samples, lats, lons, ele = getSamples(filePath, 'lat', 'lon', 'Band1', offset, (W, H), M) 20 | 21 | # Create linear 2D grid. 22 | grid = Grid2D() 23 | grid.rectlinear((W, H), (1, W), (1, H)) 24 | exe = SK(samples)# Create a sk interpolator. 25 | 26 | # Calculate a nested variogram function. 27 | nv, vbs = calculateOmnidirectionalVariogram2D(samples) 28 | indice = [i for i in range(0, len(nv.variograms), 2)] 29 | variograms = [nv.variograms[i] for i in indice] 30 | nv.variograms = variograms 31 | nv.unitVectors = nv.unitVectors[indice] 32 | 33 | # Perform interpolation of all points in the grid. 34 | grid.pro, grid.sigma = exe.execute(grid.points(), N, nv) 35 | 36 | print(exe.crossValidate(N, nv))# Perform leave-one-out validation and print result. 37 | print(exe.crossValidateKFold(10, N, nv))# Perform k-fold validation and print result. 38 | 39 | grid.pro.resize((grid.dim[1], grid.dim[0])) 40 | grid.sigma.resize((grid.dim[1], grid.dim[0])) 41 | ae = np.abs(grid.pro - ele) 42 | print("mae:", np.mean(ae)) 43 | plt.subplot(221) 44 | img2d(ele, title="origin")# Plotting original elevation data. 45 | plt.subplot(222) 46 | img2d(grid.pro, title="estimate")# Plotting interpolation results. 47 | plt.subplot(223) 48 | img2d(ae, title="error")# Plotting absolute errors. 49 | plt.subplot(224) 50 | img2d(grid.sigma, title="krige variance")# Plotting kriging variances. 51 | plt.show() 52 | -------------------------------------------------------------------------------- /examples/SK3D.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.krige import SK 2 | from tfinterpy.grid import Grid3D 3 | from tfinterpy.variogram import calculateDefaultVariogram3D 4 | from tfinterpy.gslib.fileUtils import readGslibPoints 5 | from tfinterpy.vtk.rendering import createGridActor, rendering 6 | import tfinterpy.vtk.colorMap as CM 7 | from tfinterpy.vtk.fileUtils import saveVTKGrid 8 | import matplotlib.pyplot as plt 9 | 10 | if __name__ == "__main__": 11 | filePath = "data/sample_data.gslib" 12 | N = 8 13 | df = readGslibPoints(filePath) 14 | print(df.describe()) 15 | samples = df[['x', 'y', 'z', 'porosity']].values 16 | 17 | # Create linear 3D grid. 18 | grid = Grid3D() 19 | grid.rectlinear((100, 100, 10), (samples[:, 0].min(), samples[:, 0].max()), 20 | (samples[:, 1].min(), samples[:, 1].max()), (samples[:, 2].min(), samples[:, 2].max())) 21 | exe = SK(samples, '3d')# Create a sk interpolator. 22 | 23 | vb = calculateDefaultVariogram3D(samples)# Calculate a default variogram function. 24 | plt.figure() 25 | vb.showVariogram() 26 | plt.show() 27 | 28 | # Perform interpolation of all points in the grid. 29 | grid.pro, grid.sigma = exe.execute(grid.points(), N, vb.getVariogram()) 30 | 31 | print(exe.crossValidate(N, vb.getVariogram()))# Perform leave-one-out validation and print result. 32 | print(exe.crossValidateKFold(10, N, vb.getVariogram()))# Perform k-fold validation and print result. 33 | 34 | # Create an actor representing a rectilinear grid and use the interpolation results for color mapping. 35 | actor = createGridActor(*grid.dim, grid.x, grid.y, grid.z, grid.pro, [samples[:, 3].min(), samples[:, 3].max()]) 36 | rendering(actor)# Rendering vtkActor. 37 | # Create an actor representing a rectilinear grid and use the kriging variances for color mapping. 38 | actor = createGridActor(*grid.dim, grid.x, grid.y, grid.z, grid.sigma, None, CM.Rainbow) 39 | rendering(actor)# Rendering vtkActor. 40 | saveVTKGrid('savedData/grid.vtk', actor.GetMapper().GetInput())# Save grid data(kriging variances) to vtk file. 41 | -------------------------------------------------------------------------------- /examples/SK3DWithNestVariogram.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.krige import SK 2 | from tfinterpy.grid import Grid3D 3 | from tfinterpy.variogram import calculateOmnidirectionalVariogram3D 4 | from tfinterpy.gslib.fileUtils import readGslibPoints 5 | from tfinterpy.vtk.rendering import createGridActor, rendering 6 | import tfinterpy.vtk.colorMap as CM 7 | from tfinterpy.vtk.fileUtils import saveVTKGrid 8 | from tfinterpy.utils import calcVecs 9 | import matplotlib.pyplot as plt 10 | 11 | if __name__ == "__main__": 12 | filePath = "data/sample_data.gslib" 13 | N = 8 14 | df = readGslibPoints(filePath)# Read 3d points from gslib file. 15 | print(df.describe()) 16 | samples = df[['x', 'y', 'z', 'porosity']].values 17 | 18 | # Create linear 3D grid. 19 | grid = Grid3D() 20 | grid.rectlinear((100, 100, 10), (samples[:, 0].min(), samples[:, 0].max()), 21 | (samples[:, 1].min(), samples[:, 1].max()), (samples[:, 2].min(), samples[:, 2].max())) 22 | 23 | # Calculate a nested variogram function. 24 | nestVariogram, variogramBuilders = calculateOmnidirectionalVariogram3D(samples) 25 | for vb in variogramBuilders: 26 | plt.figure() 27 | vb.showVariogram() 28 | plt.show() 29 | 30 | exe = SK(samples, '3d')# Create a sk interpolator. 31 | # Perform interpolation of all points in the grid. 32 | grid.pro, grid.sigma = exe.execute(grid.points(), N, nestVariogram) 33 | 34 | print(exe.crossValidate(N, nestVariogram))# Perform leave-one-out validation and print result. 35 | print(exe.crossValidateKFold(10, N, nestVariogram))# Perform k-fold validation and print result. 36 | # Create an actor representing a rectilinear grid and use the interpolation results for color mapping. 37 | actor = createGridActor(*grid.dim, grid.x, grid.y, grid.z, grid.pro, [samples[:, 3].min(), samples[:, 3].max()]) 38 | rendering(actor)# Rendering vtkActor. 39 | # Create an actor representing a rectilinear grid and use the kriging variances for color mapping. 40 | actor = createGridActor(*grid.dim, grid.x, grid.y, grid.z, grid.sigma, None, CM.Rainbow) 41 | rendering(actor)# Rendering vtkActor. 42 | saveVTKGrid('savedData/grid.vtk', actor.GetMapper().GetInput())# Save grid data(kriging variances) to vtk file. 43 | -------------------------------------------------------------------------------- /examples/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2022/3/10 9:41 3 | # @Author : UCCU 4 | -------------------------------------------------------------------------------- /examples/data/AustraliaTemperature20210101.csv: -------------------------------------------------------------------------------- 1 | STATION,NAME,LATITUDE,LONGITUDE,ELEVATION,TEMP 2 | 95740099999,"GUNNEDAH AIRPORT AWS, AS",-30.95,150.25,263.0,69.9 3 | 94911099999,"YANAKIE, AS",-38.8,146.2,13.9,67.1 4 | 94886099999,"POUND CREEK, AS",-38.6333333,145.8108333,3.6,67.5 5 | 95292099999,"SOUTH JOHNSTONE EXPERIMENTAL STATION, AS",-17.6,146.0,19.0,79.1 6 | 94833099999,"MOUNT WILLIAM, AS",-37.3,142.6,1150.0,61.2 7 | 94951099999,"DUNALLEY STROUD POINT, AS",-42.9,147.7833333,12.7,61.1 8 | 94768099999,"SYDNEY OBSERVATORY HILL, AS",-33.85,151.2,40.0,65.1 9 | 94846099999,"AIREYS INLET, AS",-38.45,144.1,95.0,64.6 10 | 95370099999,"WILLIAMSON, AS",-22.47,150.18,28.0,80.2 11 | 94171099999,"WEIPA, AS",-12.678611,141.925278,19.2,80.1 12 | 94332099999,"MOUNT ISA, AS",-20.663889,139.488611,341.68,84.3 13 | 94637099999,"KALGOORLIE BOULDER, AS",-30.789444,121.461667,366.67,78.3 14 | 94672099999,"ADELAIDE INTERNATIONAL, AS",-34.945,138.530556,6.09,72.2 15 | 94109099999,"MURGANELLA AIRSTRIP, AS",-11.55,132.9266667,11.5,82.3 16 | 94755099999,"CAMDEN, AS",-34.040278,150.687222,70.1,63.7 17 | 94715099999,"FORBES AIRPORT, AS",-33.3666666,147.9166666,231.0,68.2 18 | 94131099999,"TINDAL, AS",-14.521111,132.377778,135.02,84.8 19 | 94820099999,"NARACOORTE AERODROME, AS",-36.9833333,140.7333333,50.0,77.5 20 | 94860099999,"KILMORE GAP, AS",-37.3833333,144.9666666,528.0,67.2 21 | 95836099999,"TATURA INST SUSTAINABLE AG, AS",-36.4333333,145.2666666,114.0,68.5 22 | 94702099999,"HAY AIRPORT AWS, AS",-34.5333333,144.8333333,92.0,74.5 23 | 94595699999,"TELFER, AS",-21.715,122.228611,295.65,94.0 24 | 95726099999,"ORANGE AIRPORT, AS",-33.3833333,149.1333333,948.0,54.7 25 | 94450099999,"LEONORA AERO, AS",-28.8833333,121.3166666,370.0,91.3 26 | 95121099999,"MIDDLE POINT AWS, AS",-12.6,131.3,15.0,83.5 27 | 95662099999,"MINNIPA DPI, AS",-32.85,135.15,166.0,72.9 28 | 95758099999,"SCONE AIRPORT, AS",-32.0333333,150.8333333,223.0,62.7 29 | 94476099999,"OODNADATTA AIRPORT, AS",-27.55,135.45,117.0,91.8 30 | 94929099999,"BOMBALA AWS, AS",-37.0,149.2333333,762.0,54.5 31 | 94977099999,"HARTZ MOUNTAINS, AS",-43.2,146.7666666,830.0,50.5 32 | 94969099999,"LAUNCESTON TI TREE BEND, AS",-41.4166666,147.1166666,5.0,64.3 33 | 94881099999,"EILDON FIRE TOWER, AS",-37.2166666,145.8333333,638.0,64.4 34 | 95718099999,"COONAMBLE AIRPORT, AS",-30.9833333,148.3833333,182.0,72.8 35 | 94859099999,"REDESDALE, AS",-37.0166666,144.5333333,290.0,69.5 36 | 95670099999,"RAYVILLE PARK, AS",-33.7833333,138.2166666,109.0,75.8 37 | 94398099999,"BLACKWATER, AS",-23.603056,148.806944,200.25,78.9 38 | 94110099999,"OENPELLI AIRPORT, AS",-12.3333333,133.0072222,9.1,81.0 39 | 94776099999,"WILLIAMTOWN, AS",-32.795,151.834444,9.44,66.0 40 | 95369099999,"ST LAWRENCE, AS",-22.35,149.5166666,10.0,78.8 41 | 95981099999,"ST HELENS AERODROME, AS",-41.3333333,148.2666666,49.0,59.2 42 | 94763099999,"PENRITH, AS",-33.7166666,150.6833333,25.0,64.0 43 | 94943099999,"NERRIGA AWS, AS",-35.1166666,150.0833333,625.6,56.4 44 | 95761099999,"HOLSWORTHY AERODROME AWS, AS",-33.9833333,150.95,68.8,64.1 45 | 94782099999,"GOSFORD AWS, AS",-33.4333333,151.3666666,7.0,65.8 46 | 94337099999,"JULIA CREEK, AS",-20.6666666,141.7333333,124.0,80.8 47 | 94294099999,"TOWNSVILLE, AS",-19.2525,146.765278,5.48,79.6 48 | 94903099999,"FALLS CREEK AWS, AS",-36.8666666,147.2666666,1767.0,50.9 49 | 94567099999,"MARYBOROUGH, AS",-25.5166666,152.7166666,11.0,75.0 50 | 95571099999,"GRAFTON RESEARCH STATION, AS",-29.6166666,152.9666666,26.0,72.9 51 | 94562099999,"UNIVERSITY OF QUEENSLAND GATTON, AS",-27.55,152.3333333,94.0,77.0 52 | 95351099999,"BLACKALL AIRPORT, AS",-24.4166666,145.4333333,282.0,82.7 53 | 95721099999,"COWRA AIRPORT AWS, AS",-33.85,148.65,297.0,64.7 54 | 95901099999,"MOUNT BAW BAW, AS",-37.8333333,146.2666666,1520.0,52.6 55 | 94128099999,"DOUGLAS RIVER, AS",-13.8333333,131.1833333,44.0,82.1 56 | 95959099999,"LIAWENEE AWS, AS",-41.9,146.6666666,1056.0,52.0 57 | 95831099999,"WALPEUP RESEARCH, AS",-35.1166666,142.0,105.0,76.9 58 | 94972099999,"SCOTTSDALE WEST MINSTONE ROAD, AS",-41.1666666,147.4833333,198.0,59.6 59 | 95705099999,"YANCO AGRICULTURAL INSTITUTE, AS",-34.6166666,146.4333333,164.0,73.0 60 | 94573099999,"CASINO AIRPORT AWS, AS",-28.8833333,153.05,22.0,74.0 61 | 94150099999,"GOVE AIRPORT, AS",-12.2833333,136.8166666,53.0,77.1 62 | 95565099999,"HERVEY BAY AIRPORT, AS",-25.3166666,152.8833333,15.0,76.3 63 | 95322099999,"RABBIT FLAT, AS",-20.1833333,130.0166666,339.0,87.2 64 | 94463099999,"CURTIN SPRINGS, AS",-25.3166666,131.75,491.0,98.3 65 | 94908099999,"OMEO, AS",-37.1,147.6,690.0,61.8 66 | 94578099999,"BRISBANE AIRPORT, AS",-27.4166666,153.0666666,6.0,75.8 67 | 94603099999,"BADGINGARRA RESEARCH STATION, AS",-30.3333333,115.5333333,275.0,78.7 68 | 95747099999,"MURRURUNDI GAP AWS, AS",-31.7333333,150.8,730.0,57.4 69 | 95659099999,"MINLATON AERO, AS",-34.75,137.5166666,32.0,70.9 70 | 94905099999,"MOUNT HOTHAM AIRPORT, AS",-37.05,147.3333333,1293.0,54.8 71 | 94575099999,"BRISBANE ARCHERFIELD, AS",-27.570278,153.008056,19.2,75.4 72 | 94417099999,"MORAWA AIRPORT, AS",-29.2,116.0166666,272.0,82.3 73 | 95774099999,"MANGROVE MOUNTAIN AWS, AS",-33.2833333,151.2166666,305.0,60.3 74 | 94552099999,"OAKEY, AS",-27.411389,151.735278,406.9,74.3 75 | 94216099999,"KUNUNURRA, AS",-15.778056,128.7075,44.19,89.8 76 | 94875099999,"SHEPPARTON AIRPORT, AS",-36.4333333,145.4,114.0,69.6 77 | 95641099999,"WITCHCLIFFE, AS",-34.0333333,115.1,81.0,68.2 78 | 94595999999,"WANGARATTA, AS",-36.415833,146.306944,153.61,70.2 79 | 94852099999,"BALLARAT AERODROME, AS",-37.5166666,143.7833333,436.0,68.5 80 | 95286099999,"MAREEBA AIRPORT AWS, AS",-17.0666666,145.4333333,473.0,76.0 81 | 94827099999,"NHILL AERODROME, AS",-36.3166666,141.6333333,140.0,75.5 82 | 94326099999,"ALICE SPRINGS, AS",-23.806667,133.902222,545.28,85.4 83 | 95969099999,"CRESSY RESEARCH STATION, AS",-41.7333333,147.0833333,150.0,62.2 84 | 95890099999,"YARRAM AIRPORT, AS",-38.5666666,146.75,18.0,66.2 85 | 94774099999,"NEWCASTLE NOBBYS SIGNAL STATION, AS",-32.9166666,151.7833333,33.0,66.1 86 | 95482099999,"BIRDSVILLE, AS",-25.8975,139.3475,47.85,94.8 87 | 95402099999,"SHARK BAY AIRPORT, AS",-25.9,113.5833333,34.0,78.3 88 | 95807099999,"KINGSTONE AERO, AS",-35.7166666,137.5166666,6.0,66.0 89 | 95480099999,"MARREE AERO, AS",-29.6666666,138.0666666,51.0,89.6 90 | 95204099999,"WEST ROEBUCK, AS",-17.9,122.3166666,32.0,88.0 91 | 94766099999,"CANTERBURY RACECOURSE, AS",-33.9,151.1166666,3.0,65.5 92 | 95667099999,"CLARE HIGH SCHOOL, AS",-33.8166666,138.6,396.0,75.9 93 | 95637099999,"LAKE GRACE, AS",-33.1,118.4666666,286.0,68.9 94 | 94878099999,"HUNTERS HILL, AS",-36.2166666,147.5333333,981.0,59.2 95 | 94913099999,"GELANTIPY, AS",-37.2166666,148.2666666,756.0,58.7 96 | 94685099999,"KADINA, AS",-33.97,137.67,42.0,75.4 97 | 94750099999,"NOWRA, AS",-34.948889,150.536944,121.92,63.7 98 | 94662099999,"CLEVE AERODROME, AS",-33.7166666,136.5,176.0,68.9 99 | 95916099999,"CABRAMURRA SMHEA, AS",-35.9333333,148.3833333,1483.0,51.5 100 | 95638099999,"ESPERANCE AERO, AS",-33.6833333,121.8333333,144.0,65.7 101 | 94935099999,"MALLACOOTA, AS",-37.6,149.7333333,22.0,63.7 102 | 95753099999,"RICHMOND RAAF, AS",-33.6,150.7833333,20.0,63.8 103 | 94964099999,"BUSHY PARK BUSHY PARK ESTATES, AS",-42.7166666,146.9,27.0,61.5 104 | 94854099999,"AVALON AIRPORT, AS",-38.0333333,144.4666666,11.0,70.6 105 | 94691099999,"BROKEN HILL AIRPORT AWS, AS",-32.0,141.4666666,282.0,82.6 106 | 94921099999,"COOMA AIRPORT AWS, AS",-36.3,148.9666666,931.0,56.3 107 | 94856099999,"GEELONG CITY, AS",-38.083,144.333,55.0,68.2 108 | 95527099999,"MOREE AERO, AS",-29.4914,149.8458,218.5,78.9 109 | 94595599999,"GOVE, AS",-12.269444,136.818333,58.52,77.5 110 | 95295099999,"AYR DPI RESEARCH STATION, AS",-19.6166666,147.3833333,12.0,79.3 111 | 95632099999,"BRIDGETOWN, AS",-33.95,116.1333333,179.0,68.7 112 | 94217099999,"ARGYLE AERODROME, AS",-16.6333333,128.45,165.0,91.7 113 | 95957099999,"WYNYARD AIRPORT, AS",-41.0,145.7333333,12.0,62.4 114 | 94863099999,"SHEOAKS AWS, AS",-37.9,144.1166666,237.0,68.7 115 | 95839099999,"HORSHAM AERODROME, AS",-36.6666666,142.1666666,134.0,72.9 116 | 94106099999,"NGUKURR AIRPORT, AS",-14.7166666,134.75,14.0,79.3 117 | 94765099999,"SYDNEY BANKSTOWN, AS",-33.924444,150.988333,8.83,65.3 118 | 94760099999,"HORSLEY EQUESTRIAN CENTRE, AS",-33.85,150.85,100.0,63.2 119 | 94647099999,"EUCLA, AS",-31.6797,128.8792,102.3,66.1 120 | 94595399999,"CURTIN, AS",-17.581389,123.828333,91.44,88.5 121 | 94641099999,"KATANNING, AS",-33.6833333,117.6,321.0,66.0 122 | 94914099999,"COMBIENBAR, AS",-37.3333333,149.0166666,641.0,58.6 123 | 95625099999,"CUNDERDIN AIRFIELD, AS",-31.6166666,117.2166666,217.0,76.9 124 | 95640099999,"WANDERING, AS",-32.6666666,116.6666666,275.0,72.6 125 | 94100099999,"KALUMBURU, AS",-14.3,126.6333333,24.0,85.0 126 | 94811099999,"SECOND VALLEY FOREST, AS",-35.5666666,138.2833333,342.0,61.0 127 | 94926099999,"CANBERRA, AS",-35.306944,149.195,574.85,61.1 128 | 94753099999,"RICHMOND, AS",-33.600556,150.780833,20.42,63.9 129 | 95617099999,"SHANNON, AS",-34.5833333,116.35,191.0,64.5 130 | 95909099999,"THREDBO AWS, AS",-36.5,148.2833333,1368.0,46.7 131 | 94655099999,"TARCOOLA, AS",-30.7166666,134.5833333,124.0,83.9 132 | 94474099999,"PUKATJA, AS",-26.2666666,132.1833333,704.0,87.9 133 | 95952099999,"MOUNT READ, AS",-41.85,145.5333333,1120.0,51.1 134 | 94595799999,"TENNANT CREEK, AS",-19.634444,134.183333,376.73,91.1 135 | 95784099999,"TAREE AIRPORT AWS, AS",-31.8833333,152.5166666,9.0,69.8 136 | 94857099999,"GEELONG RACECOURSE, AS",-38.1666666,144.3666666,35.0,70.8 137 | 94712099999,"YOUNG AIRPORT, AS",-34.25,148.25,381.0,64.7 138 | 94752099999,"BADGERY S CREEK AIRPORT, AS",-33.9,150.7333333,82.0,63.3 139 | 94927099999,"BRAIDWOOD RACECOURSE AWS, AS",-35.4333333,149.7833333,666.0,56.0 140 | 94817099999,"COONAWARRA, AS",-37.3,140.8166666,58.0,76.3 141 | 95305099999,"ONSLOW AIRPORT, AS",-21.6666666,115.1166666,11.0,87.2 142 | 94862099999,"YARRAWONGA, AS",-36.0166666,146.0333333,129.0,71.9 143 | 94376099999,"THANGOOL AIRPORT, AS",-24.4833333,150.5666666,199.0,76.5 144 | 94370099999,"SAMUEL HILL AERO, AS",-22.7333333,150.65,32.0,78.7 145 | 95728099999,"COONABARABRAN AIRPORT AWS, AS",-31.3166666,149.2666666,646.0,64.7 146 | 94596099999,"BALLINA AIRPORT AWS, AS",-28.8333333,153.55,2.0,74.4 147 | 94759099999,"TERREY HILLS AWS, AS",-33.6833333,151.2333333,199.0,61.8 148 | 94105099999,"NOONAMAH AIRSTRIP, AS",-12.6166666,131.05,17.5,82.5 149 | 94308099999,"ROEBOURNE AERO, AS",-20.75,117.15,11.0,91.7 150 | 94260099999,"BURKETOWN AIRPORT, AS",-17.75,139.5333333,6.0,81.1 151 | 95845099999,"MOUNT GELLIBRAND, AS",-38.2333333,143.7833333,262.0,65.5 152 | 94588099999,"GLEN INNES AIRPORT, AS",-29.6833333,151.7,1045.0,65.7 153 | 94381099999,"GLADSTONE AIRPORT, AS",-23.8666666,151.2166666,17.0,79.6 154 | 94653099999,"CEDUNA AMO, AS",-32.1333333,133.7,16.0,67.7 155 | 95960099999,"DEVONPORT AIRPORT, AS",-41.1666666,146.4166666,10.0,63.1 156 | 94600099999,"CAPE NATURALISTE, AS",-33.5333333,115.0166666,110.0,72.9 157 | 94925099999,"TUGGERANONG ISABELLA PLAINS, AS",-35.4166666,149.1,588.0,61.6 158 | 94980099999,"FLINDERS ISLAND AIRPORT, AS",-40.1,148.0,10.0,62.5 159 | 94374099999,"ROCKHAMPTON, AS",-23.381944,150.475278,10.36,79.8 160 | 94542099999,"DALBY AIRPORT, AS",-27.15,151.2666666,348.0,75.3 161 | 95629099999,"DALWALLINU, AS",-30.2833333,116.6666666,326.0,80.2 162 | 94968099999,"LAUNCESTON, AS",-41.545278,147.214167,171.29,60.7 163 | 95734099999,"NARRABRI AIRPORT AWS, AS",-30.3166666,149.8166666,230.0,72.9 164 | 94757099999,"CAMBELL TOWN MOUNT ANNAN, AS",-34.0666666,150.7666666,112.0,63.1 165 | 95566099999,"BEERBURRUM FOREST STATION, AS",-26.95,152.9666666,36.0,72.7 166 | 95676099999,"EDINBURGH, AS",-34.7025,138.620833,20.42,75.9 167 | 94930099999,"MOUNT NOWA NOWA, AS",-37.7,148.0833333,350.0,64.8 168 | 94807099999,"PARDANA CFS AWS, AS",-35.8,137.25,165.0,63.9 169 | 94872099999,"FERNY CREEK, AS",-37.8666666,145.3333333,561.0,67.7 170 | 94152099999,"BORROLOOLA, AS",-16.0833333,136.3,17.0,81.5 171 | 94754099999,"NULLO MOUNTAIN AWS, AS",-32.7333333,150.2333333,1130.0,52.3 172 | 95958099999,"SCOTTS PEAK DAM, AS",-43.05,146.2666666,408.0,60.6 173 | 94711099999,"COBAR MO, AS",-31.4833333,145.8333333,263.6,74.6 174 | 94749099999,"BELLAMBI AWS, AS",-34.3833333,150.9333333,10.0,64.3 175 | 95575099999,"BEAUDESERT DRUMLEY ST, AS",-27.9666666,152.9833333,48.0,75.2 176 | 94864099999,"MELBOURNE ESSENDON, AS",-37.728056,144.901944,85.95,70.1 177 | 94373099999,"YEPPOON THE ESPLANADE, AS",-23.1333333,150.75,6.0,79.5 178 | 94808099999,"NOARLUNGA, AS",-35.1666666,138.5,55.0,73.1 179 | 94317099999,"NEWMAN AERO, AS",-23.4166666,119.8,524.0,94.6 180 | 94212099999,"HALLS CREEK AIRPORT, AS",-18.2333333,127.6666666,424.0,88.6 181 | 95677099999,"ADELAIDE PARAFIELD, AS",-34.793333,138.633056,17.37,76.4 182 | 94703099999,"BOURKE AIRPORT AWS, AS",-30.0333333,145.95,108.0,76.2 183 | 94153099999,"GROOTE EYLANDT, AS",-13.975,136.46,16.15,79.8 184 | 94710099999,"COBAR AIRPORT AWS, AS",-31.5333333,145.8,218.0,74.8 185 | 94367099999,"MACKAY MO, AS",-21.1166666,149.2166666,33.0,78.7 186 | 95962099999,"WARRA, AS",-43.0666666,146.7,495.0,54.5 187 | 94865099999,"LAVERTON RAAF, AS",-37.8666666,144.75,20.0,72.9 188 | 94592099999,"GOLD COAST, AS",-28.164444,153.504722,6.4,74.7 189 | 94870099999,"MELBOURNE MOORABBIN, AS",-37.975833,145.102222,15.24,72.2 190 | 94975099999,"HOBART, AS",-42.836111,147.510278,3.96,60.3 191 | 94206099999,"FITZROY CROSSING AERO, AS",-18.1833333,125.5666666,115.0,90.7 192 | 94321099999,"WULUNGURRU, AS",-23.2666666,129.3666666,455.0,94.8 193 | 95458099999,"COOBER PEDY AIRPORT, AS",-29.0333333,134.7166666,226.0,88.5 194 | 94316099999,"PARABURDOO AERO, AS",-23.1666666,117.75,424.0,94.9 195 | 95956099999,"LUNCHERON HILL FORESTRY, AS",-41.15,145.15,340.0,58.7 196 | 94541099999,"INVERELL RESEARCH CENTRE, AS",-29.7833333,151.0833333,664.0,71.7 197 | 95678099999,"MOUNT LOFTY, AS",-34.9666666,138.7,730.0,69.2 198 | 94919099999,"KHANCOBAN, AS",-36.2333333,148.1333333,340.0,63.5 199 | 94814099999,"STRATHALBYN RACECOURSE, AS",-35.2833333,138.9,58.0,67.4 200 | 94651099999,"NULLARBOR, AS",-31.45,130.9,65.0,67.7 201 | 94809099999,"EDITHBURGH AWS, AS",-35.1166666,137.7333333,7.0,66.0 202 | 94866099999,"MELBOURNE INTERNATIONAL, AS",-37.673333,144.843333,132.28,73.8 203 | 94365099999,"PROSERPINE WHITSUNDAY COAST, AS",-20.495,148.552222,24.99,78.7 204 | 95642099999,"NORSEMAN AERO, AS",-32.2166666,121.75,263.0,74.4 205 | 94312099999,"PORT HEDLAND INTERNATIONAL, AS",-20.377778,118.626389,10.05,89.8 206 | 94617099999,"MANJIMUP, AS",-34.25,116.15,287.0,65.5 207 | 94234099999,"DALY WATERS AWS, AS",-16.25,133.3666666,211.0,87.5 208 | 95481099999,"MOOMBA AIRPORT, AS",-28.1,140.2,38.0,90.5 209 | 94840099999,"MORTLAKE RACECOURSE, AS",-38.0666666,142.7666666,131.0,69.1 210 | 94775099999,"TOCAL AWS, AS",-32.6333333,151.5833333,30.0,64.1 211 | 95323099999,"ARLTUNGA, AS",-23.4666666,134.6833333,664.0,91.9 212 | 94604099999,"BUNBURY, AS",-33.35,115.65,6.0,74.6 213 | 94274099999,"GEORGETOWN AIRPORT, AS",-18.3,143.5333333,302.0,76.5 214 | 95205099999,"DERBY AERO, AS",-17.3666666,123.6666666,7.0,88.6 215 | 95816099999,"ROBE AIRFIELD, AS",-37.1833333,139.8,4.0,66.2 216 | 94957099999,"OUSE FIRE STATION, AS",-42.4833333,146.7166666,91.0,60.5 217 | 94762099999,"HOLSWORTHY CONTROL RANGE, AS",-33.9833333,150.9166666,40.0,72.9 218 | 95706099999,"NARRANDERA, AS",-34.702222,146.512222,144.47,73.4 219 | 95974099999,"FINGAL LEGGE STREET, AS",-41.6333333,147.9666666,237.0,57.0 220 | 95896099999,"ALBURY AEROPORT, AS",-36.0666666,146.95,165.0,71.6 221 | 94684099999,"YUNTA AIRSTRIP, AS",-32.5666666,139.5666666,300.0,80.9 222 | 95572099999,"NAMBOUR DPI HILLSIDE, AS",-26.65,152.9333333,33.0,73.9 223 | 94839099999,"CHARLTON, AS",-36.2833333,143.35,132.0,75.8 224 | 94566099999,"GYMPIE, AS",-26.1833333,152.6333333,65.0,74.4 225 | 94338099999,"TREPELL AIRPORT, AS",-21.8333333,140.8833333,267.0,84.4 226 | 94255099999,"CAMOOWEAL TOWNSHIP, AS",-19.9166666,138.1166666,232.0,87.3 227 | 94821099999,"MOUNT GAMBIER AERO, AS",-37.7333333,140.7833333,69.0,73.4 228 | 95647099999,"NORTH WALPOLE, AS",-34.95,116.7166666,74.0,65.2 229 | 95687099999,"RENMARK AERO, AS",-34.2,140.6833333,32.0,82.2 230 | 94678099999,"MOUNT CRAWFORD AWS, AS",-34.7333333,138.9333333,525.0,72.0 231 | 94261099999,"CENTURY MINE, AS",-18.75,138.7,127.0,83.4 232 | 94898099999,"CERBERUS AWS, AS",-38.35,145.1666666,14.0,70.9 233 | 95634099999,"SOUTHERN CROSS AIRFIELD, AS",-31.2333333,119.35,348.0,80.1 234 | 95837099999,"RUTHERGLEN RESEARCH, AS",-36.1,146.5,175.0,70.9 235 | 94910099999,"WAGGA WAGGA, AS",-35.165278,147.466389,220.67,70.4 236 | 94239099999,"MCARTHUR RIVER MINE, AS",-16.4333333,136.0666666,41.0,81.5 237 | 95293099999,"WOOLSHED, AS",-19.4166666,146.5333333,559.0,73.7 238 | 94399099999,"LOCHINGTON, AS",-23.9333333,147.5166666,267.0,79.9 239 | 94609099999,"JANDAKOT AERO, AS",-32.1,115.8833333,31.0,79.8 240 | 94429099999,"MOUNT MAGNET AERO, AS",-28.1166666,117.8333333,408.0,89.4 241 | 95913099999,"MOUNT MOORNAPA, AS",-37.75,147.1333333,480.0,62.0 242 | 95663099999,"CUMMINS AERO, AS",-34.25,135.7166666,58.0,69.4 243 | 94631099999,"ROCKY GULLY, AS",-34.5666666,117.0166666,251.0,63.9 244 | 95773099999,"ARMIDALE AIRPORT AWS, AS",-30.5333333,151.6166666,1081.0,62.7 245 | 94874099999,"MANGALORE AIRPORT, AS",-36.8833333,145.1833333,141.0,68.9 246 | 95717099999,"PARKES AIRPORT, AS",-33.1333333,148.2333333,324.0,65.9 247 | 95835099999,"LONGERENONG, AS",-36.6666666,142.3,133.0,74.2 248 | 95570099999,"GRAFTON AIRPORT, AS",-29.75,153.0333333,26.0,72.4 249 | 94188099999,"CAPE FLATTERY, AS",-14.9666666,145.3166666,19.0,81.7 250 | 94598099999,"EVANS HEAD RAAF BOMBING RANGE, AS",-29.1833333,153.4,63.0,71.2 251 | 94610099999,"PERTH INTERNATIONAL, AS",-31.940278,115.966944,20.42,80.0 252 | 94276099999,"PALMERVILLE, AS",-16.0,144.0666666,205.0,79.2 253 | 94341099999,"RICHMOND, AS",-20.701944,143.114722,206.04,81.5 254 | 94555099999,"WARWICK, AS",-28.2,152.1,476.0,72.4 255 | 95671099999,"ROSEWORTHY AG COLLEGE, AS",-34.5166666,138.6833333,65.0,75.2 256 | 95832099999,"EDENHOPE AIRPORT, AS",-37.0166666,141.2666666,155.0,74.9 257 | 94915099999,"PERISHER VALLEY AWS, AS",-36.4,148.4,1735.0,48.2 258 | 95639099999,"SALMON GUMS RES. STATION, AS",-32.9833333,121.6166666,249.0,68.1 259 | 95754099999,"MERRIWA ROSCOMMON, AS",-32.1833333,150.1666666,376.0,61.5 260 | 95704099999,"GRIFFITH AIRPORT AWS, AS",-34.25,146.0666666,135.0,71.4 261 | 94938099999,"ULLADULLA AWS, AS",-35.35,150.4833333,37.0,65.6 262 | 95621099999,"COLLIE EAST, AS",-33.3666666,116.1666666,200.0,71.0 263 | 94690099999,"AUSTIN PLAINS, AS",-35.3777778,140.5377778,110.8,78.9 264 | 95448099999,"LEINSTER AERO, AS",-27.85,120.7,498.0,93.9 265 | 95636099999,"JACUP, AS",-33.8833333,119.1,306.0,62.6 266 | 94659099999,"WOOMERA, AS",-31.144167,136.816944,167.03,84.5 267 | 94306099999,"MARDIE, AS",-21.1833333,115.9666666,12.0,89.4 268 | 94268099999,"KOWANYAMA AIRPORT, AS",-15.4833333,141.75,11.0,79.0 269 | 95966099999,"LAUNCESTON AIRPORT, AS",-41.55,147.2166666,168.0,60.6 270 | 95918099999,"ORBOST, AS",-37.6833333,148.4666666,63.0,67.8 271 | 94746099999,"MOSS VALE AWS, AS",-34.5166666,150.4166666,679.0,56.3 272 | 95307099999,"KARRATHA AERO, AS",-20.7166666,116.7666666,6.0,89.5 273 | 94363099999,"EMERALD AIRPORT, AS",-23.5666666,148.1833333,190.0,80.4 274 | 94553099999,"APPLETHORPE, AS",-28.6166666,151.95,873.0,67.0 275 | 95529099999,"MILES CONSTANCE STREET, AS",-26.65,150.1833333,305.0,79.5 276 | 95840099999,"WESTMERE, AS",-37.7,142.9333333,227.0,70.4 277 | 94743099999,"MOUNT BOYCE, AS",-33.6166666,150.2666666,1080.0,51.0 278 | 94137099999,"JABIRU AIRPORT, AS",-12.6666666,132.9,28.0,81.0 279 | 94595899999,"TAREE, AS",-31.888611,152.513889,11.58,70.0 280 | 94906099999,"MOUNT HOTHAM, AS",-36.9666666,147.1333333,1849.0,49.4 281 | 94628099999,"NEWDEGATE RES. STATION, AS",-33.1166666,118.8333333,321.0,67.8 282 | 94143099999,"BULMAN AWS, AS",-13.6666666,134.3333333,105.0,76.9 283 | 94327099999,"JERVOIS, AS",-22.95,136.15,329.0,92.2 284 | 94855099999,"BENDIGO AIRPORT AWS, AS",-36.7333333,144.3166666,209.0,69.5 285 | 94612099999,"PEARCE, AS",-31.667778,116.015,45.41,81.0 286 | 95972099999,"CAMPANIA KINKORA, AS",-42.6833333,147.4166666,45.0,59.4 287 | 95719099999,"DUBBO AIRPORT AWS, AS",-32.2166666,148.5666666,285.0,66.4 288 | 95283099999,"COOKTOWN AIRPORT, AS",-15.45,145.1833333,6.0,80.6 289 | 94767099999,"SYDNEY INTERNATIONAL, AS",-33.946111,151.177222,6.4,66.8 290 | 94912099999,"BAIRNSDALE AIRPORT, AS",-37.8833333,147.5666666,50.0,64.3 291 | 95666099999,"PORT AUGUSTA ARID LANDS, AS",-32.5166666,137.7166666,14.0,81.0 292 | 94907099999,"EAST SALE, AS",-38.098889,147.149444,7.01,66.3 293 | 94802099999,"ALBANY AIRPORT, AS",-34.9414,117.8022,69.0,64.7 294 | 94959099999,"BUTLERS GORGE, AS",-42.2833333,146.2833333,667.0,55.7 295 | 94328099999,"TERRITORY GRAPE FARM, AS",-22.45,133.6333333,567.0,86.1 296 | 94987099999,"FRIENDLY BEACHES, AS",-42.0,148.2833333,56.0,60.1 297 | 94170099999,"WEIPA AERO, AS",-12.6833333,141.9166666,19.0,80.7 298 | 94576099999,"BRISBANE, AS",-27.4833333,153.0333333,8.0,76.1 299 | 95748099999,"WOLLONGONG AIRPORT, AS",-34.5666666,150.7833333,8.0,64.3 300 | 94686099999,"FOWLERS GAP AWS, AS",-31.0833333,141.7,182.0,81.8 301 | 94200099999,"MANDORA, AS",-19.7333333,120.85,8.0,89.3 302 | 95612099999,"GINGIN AERO, AS",-31.4666666,115.8666666,75.0,79.1 303 | 94335099999,"CLONCURRY AIRPORT, AS",-20.6666666,140.5,187.0,80.5 304 | 94896099999,"ALBURY, AS",-36.067778,146.958056,164.28,71.6 305 | 94836099999,"STAWELL AERODROME, AS",-37.0666666,142.7333333,235.0,72.4 306 | 94302099999,"LEARMONTH, AS",-22.235556,114.088611,5.79,89.3 307 | 94843099999,"SWAN HILL AERODROME, AS",-35.3833333,143.5333333,71.0,76.9 308 | 94682099999,"LOXTON RESEARCH CENTRE, AS",-34.4333333,140.6,30.0,81.1 309 | 94141099999,"CENTRAL ARNHEM PLATEAU, AS",-13.3333333,133.0833333,416.0,77.8 310 | 95977099999,"GROVE RESEARCH STATION, AS",-42.9833333,147.0666666,65.0,56.5 311 | 95937099999,"MORUYA AIRPORT, AS",-35.9,150.15,4.0,65.0 312 | 94850099999,"KING ISLAND AIRPORT, AS",-39.8833333,143.8833333,38.0,63.1 313 | 94785099999,"KEMPSEY AIRPORT AWS, AS",-31.0666666,152.7666666,14.0,71.1 314 | 94549099999,"KINGAROY AIRPORT, AS",-26.5666666,151.8333333,434.0,70.7 315 | 94873199999,"PUCKAPUNYAL LYON HILL DEFENCE, AS",-36.94,145.05,193.0,69.7 316 | 94569099999,"SUNSHINE COAST AIRPORT, AS",-26.6,153.1,4.0,78.1 317 | 94395099999,"CLERMONT AIRPORT, AS",-22.7833333,147.6166666,272.0,79.0 318 | 95931099999,"BEGA AWS, AS",-36.6666666,149.8166666,42.0,63.3 319 | 94895599999,"AVALON, AS",-38.039444,144.469444,10.66,70.4 320 | 95715099999,"WALGETT AIRPORT, AS",-30.0333333,148.1166666,134.0,77.0 321 | 95833099999,"KYABRAM INST SUSTAINABLE AG, AS",-36.3333333,145.0666666,104.0,69.1 322 | 94786099999,"PORT MACQUARIE AIRPORT AWS, AS",-31.4333333,152.85,5.0,72.1 323 | 95925099999,"MOUNT GININI, AS",-35.5333333,148.7666666,1760.0,46.1 324 | 94828099999,"PORTLAND CASHMORE AIRPORT, AS",-38.3166666,141.4666666,82.0,67.5 325 | 94225099999,"DELAMERE WEAPONS RANGE, AS",-15.75,131.9166666,222.0,86.6 326 | 94140099999,"MILINGIMBI AWS, AS",-12.1166666,134.9,16.0,79.5 327 | 95722099999,"TEMORA AIRPORT, AS",-34.4333333,147.5166666,281.0,69.1 328 | 95697099999,"IVANHOE AERODROME AWS, AS",-32.8833333,144.3166666,100.0,76.9 329 | 94608099999,"PERTH METRO, AS",-31.9166666,115.8666666,25.0,79.8 330 | 94510099999,"CHARLEVILLE, AS",-26.413334,146.2625,305.71,86.1 331 | 94517099999,"ST GEORGE AIRPORT, AS",-28.05,148.6,199.0,85.2 332 | 94835099999,"BEN NEVIS, AS",-37.2333333,143.2,875.0,64.5 333 | 95867099999,"SCORESBY RESEARCH INSTITUTE, AS",-37.8666666,145.25,80.0,72.5 334 | 94595199999,"AMBERLEY, AS",-27.640556,152.711944,27.73,76.3 335 | 94186099999,"LOCKHART RIVER AIRPORT, AS",-12.7833333,143.3,20.0,80.0 336 | 94231099999,"LAJAMANU, AS",-18.3333333,130.6333333,317.0,88.1 337 | 94387099999,"BUNDABERG AERO, AS",-24.9,152.3166666,28.0,75.8 338 | 94615099999,"GOOSEBERY HILL, AS",-31.95,116.05,220.0,77.7 339 | 95664099999,"WHYALLA, AS",-33.058889,137.514444,12.49,73.1 340 | 95827099999,"KANAGULK, AS",-37.1166666,141.8,189.0,74.6 341 | 94572099999,"LISMORE AIRPORT AWS, AS",-28.8333333,153.26,9.8,74.0 342 | 95611099999,"BUSSELTON AERO, AS",-33.6833333,115.4,17.0,72.4 343 | 94719099999,"DUBBO, AS",-32.216667,148.574722,284.98,66.2 344 | 94955099999,"SHEFFIELD SCHOOL FARM, AS",-41.3833333,146.3166666,295.0,59.3 345 | 94960099999,"TUNNAK FIRE STATION, AS",-42.45,147.4666666,462.0,52.9 346 | 95646099999,"FORREST, AS",-30.8333333,128.1166666,160.0,73.4 347 | 95936099999,"MELBOURNE OLYMPIC PARK, AS",-37.8333333,144.9833333,7.5,74.8 348 | 95866099999,"ESSENDON AIRPORT, AS",-37.7333333,144.9,79.0,74.8 349 | 94342099999,"WINTON AIRPORT, AS",-22.3666666,143.0833333,193.0,86.5 350 | 95716099999,"GOULBURN AIRPORT AWS, AS",-34.8166666,149.7333333,641.0,56.8 351 | 94614099999,"SWANBOURNE, AS",-31.95,115.7666666,41.0,76.2 352 | 94336099999,"THE MONUMENT AIRPORT, AS",-21.8,139.9166666,289.0,87.2 353 | 94232099999,"VICTORIA RIVER DOWNS, AS",-16.4,131.0166666,90.0,88.1 354 | 94683099999,"KUITPO FOREST RESERVE, AS",-35.1666666,138.6666666,365.0,67.8 355 | 94891099999,"LATROBE VALLEY AIRPORT, AS",-38.2166666,146.4666666,56.0,66.5 356 | 94238099999,"TENNANT CREEK AIRPORT, AS",-19.6333333,134.1833333,377.0,91.3 357 | 95658099999,"OLYMPIC DAM AERODROME, AS",-30.4833333,136.8833333,100.0,86.4 358 | 95710099999,"TRANGIE RESEARCH STATION, AS",-31.9833333,147.95,216.0,70.4 359 | 94829099999,"HAMILTON AIRPORT, AS",-37.65,142.0666666,242.0,71.3 360 | 95317099999,"MARBLE BAR, AS",-21.1833333,119.75,183.0,95.6 361 | 95485099999,"TIBOOBURRA, AS",-29.451111,142.057778,178.0,83.6 362 | 95815099999,"MUNKORA, AS",-36.1,140.3166666,28.0,74.6 363 | 94515099999,"ROMA AIRPORT, AS",-26.55,148.7833333,304.0,82.4 364 | 95825099999,"CASTERTON, AS",-37.5833333,141.3333333,131.0,74.6 365 | 94620099999,"DWELLINGUP, AS",-32.7166666,116.05,268.0,72.7 366 | 95822099999,"DARTMOOR, AS",-37.9166666,141.2666666,51.0,72.7 367 | 95767099999,"LAKE MACQUARIE AWS, AS",-33.0833333,151.4666666,6.0,65.4 368 | 94457099999,"WARBURTON AIRFIELD, AS",-26.1333333,126.5833333,460.0,93.9 369 | 95699099999,"WHITE CLIFFS AWS, AS",-30.85,143.07,158.0,80.7 370 | 94729099999,"BATHURST AIRPORT AWS, AS",-33.4166666,149.65,745.0,57.7 371 | 95929099999,"MERIMBULA AIRPORT, AS",-36.9166666,149.9,2.0,64.9 372 | 95543099999,"GAYNDAH AIRPORT, AS",-25.6166666,151.6166666,112.0,76.6 373 | 94346099999,"LONGREACH AERO, AS",-23.4333333,144.2833333,192.0,84.8 374 | 94791099999,"COFFS HARBOUR, AS",-30.3205556,153.1163889,5.0,72.5 375 | 95610099999,"KALAMUNDA BICKLEY, AS",-32.0166666,116.1333333,385.0,73.7 376 | 94288099999,"CAIRNS RACECOURSE, AS",-16.95,145.75,401.0,79.6 377 | 94343099999,"HUGHENDEN AIRPORT, AS",-20.8166666,144.2333333,316.0,80.8 378 | 95214099999,"WYNDHAM AERO, AS",-15.5,128.15,4.0,91.9 379 | 94130099999,"BRADSHAW, AS",-14.95,130.8,76.0,90.2 380 | 94681099999,"NURIOOTPA VITICULTURAL, AS",-34.4833333,139.0,276.0,75.5 381 | 95487099999,"BALLERA GAS FIELD, AS",-27.4166666,141.8166666,115.0,88.3 382 | 94838099999,"HOPETOUN AIRPORT, AS",-35.7166666,142.35,78.0,74.4 383 | 95765099999,"SYDNEY OLYMPIC PARK AWS ARCHERY CENTRE, AS",-33.8333333,151.0666666,4.0,65.8 384 | 94461099999,"GILES METEOROLOGICAL OFFICE, AS",-25.0333333,128.3,599.0,90.6 385 | 94183099999,"COEN AIRPORT, AS",-13.7666666,143.1166666,160.0,78.2 386 | 94396099999,"ROLLESTON AIRPORT, AS",-24.4666666,148.6333333,220.0,79.6 387 | 95771099999,"CESSNOCK AIRPORT, AS",-32.7833333,151.3333333,62.0,64.8 388 | 95654099999,"WUDINNA AERO, AS",-33.05,135.45,87.0,75.0 389 | 95709099999,"WEST WYALONG AIRPORT AWS, AS",-33.9333333,147.2,258.0,67.9 390 | 95551099999,"TOOWOOMBA AIRPORT, AS",-27.55,151.9166666,642.0,69.6 391 | 94344099999,"URANDANGI AERODROME, AS",-21.6,138.3666666,75.0,92.2 392 | 95874099999,"VIEWBANK ARPNSA, AS",-37.7333333,145.1,66.0,73.9 393 | 94837099999,"WARRNAMBOOL AIRPORT NDB, AS",-38.2833333,142.45,71.0,70.1 394 | 94449099999,"LAVERTON AERO, AS",-28.6166666,122.4166666,465.0,89.4 395 | 94397099999,"MORANBAH, AS",-22.057778,148.0775,234.69,79.1 396 | 94727099999,"MUDGEE AIRPORT AWS, AS",-32.5666666,149.6166666,472.0,62.8 397 | 94570099999,"TEWANTIN RSL PARK, AS",-26.3833333,153.0333333,7.0,77.2 398 | 95869099999,"DENILIQUIN AIRPORT AWS, AS",-35.5666666,144.95,95.0,73.2 399 | 94287099999,"CAIRNS INTERNATIONAL, AS",-16.885833,145.755278,3.04,79.5 400 | 95979099999,"MOUNT WELLINGTON, AS",-42.9,147.2333333,1260.5,44.0 401 | 94674099999,"PORT LINCOLN, AS",-34.605278,135.880278,10.97,66.1 402 | 95823099999,"PADTHAWAY SOUTH, AS",-36.65,140.5166666,35.0,76.1 403 | 95111099999,"PORT KEATS AIRPORT, AS",-14.25,129.5333333,29.0,87.3 404 | 94125099999,"BATCHELOR AERO, AS",-13.05,131.0166666,105.0,83.5 405 | 95818099999,"PALLAMANA AERODROME, AS",-35.0666666,139.2333333,46.0,70.3 406 | 95708099999,"CONDOBOLIN AIRPORT, AS",-33.0666666,147.2166666,194.0,71.2 407 | 94894099999,"MOUNT BULLER AWS, AS",-37.15,146.4333333,1707.0,51.3 408 | 95492099999,"THARGOMINDAH, AS",-27.986389,143.810833,131.97,82.9 409 | 94889099999,"WANGARATTA AERO, AS",-36.4166666,146.3,153.0,69.9 410 | 94403099999,"GERALDTON, AS",-28.796111,114.7075,36.88,75.4 411 | -------------------------------------------------------------------------------- /examples/data/sample_data.gslib: -------------------------------------------------------------------------------- 1 | # 2 | 5 3 | x 4 | y 5 | z 6 | porosity 7 | impedance 8 | 51 12 6 0.315 8754.48 9 | 51 12 7 0.309 8545.85 10 | 51 12 8 0.304 8341.22 11 | 24 50 1 0.292 7752.68 12 | 24 50 2 0.283 7663.65 13 | 24 50 3 0.253779 7644.15 14 | 24 50 4 0.259107 7658.44 15 | 0 4 5 0.324 6394.14 16 | 0 4 6 0.306 6535.19 17 | 71 80 7 0.314581 8546.87 18 | 71 80 8 0.312 8561.47 19 | 40 11 3 0.281 9204.04 20 | 40 11 4 0.301 8962.13 21 | 40 11 7 0.304 8775.5 22 | 40 11 8 0.317 8557.07 23 | 40 11 9 0.272 8249.47 24 | 84 6 2 0.269 9254.27 25 | 84 6 3 0.319 8936.03 26 | 19 35 1 0.278 9042.8 27 | 19 35 2 0.286 9222.36 28 | 69 114 0 0.291 8710.99 29 | 69 114 2 0.315 8278.49 30 | 69 114 3 0.2566 8098.95 31 | 69 114 4 0.31 7940.24 32 | 69 114 5 0.268 7805.64 33 | 69 114 8 0.304 7608.57 34 | 69 114 9 0.302 7608.56 35 | 99 51 1 0.263 8840.69 36 | 99 51 2 0.255 8824.67 37 | 44 34 6 0.299 7693.43 38 | 44 34 7 0.287 7642.95 39 | 44 34 8 0.325 7597.87 40 | 44 34 9 0.294 7556.49 41 | 31 54 4 0.308 9470.45 42 | 31 54 5 0.275 9105.9 43 | 31 54 6 0.301 8741.91 44 | 51 9 6 0.322 8600.02 45 | 51 9 7 0.306 8744.51 46 | 51 9 8 0.3258 8882.39 47 | 94 115 1 0.245221 8845.37 48 | 94 115 2 0.287 8587.12 49 | 94 115 3 0.271 8338.7 50 | 94 115 4 0.314 8133.23 51 | 94 115 5 0.289 8007.09 52 | 3 37 2 0.288554 7639.31 53 | 3 37 3 0.285 7353.15 54 | 3 37 4 0.297 7255.95 55 | 3 37 5 0.353 7344.63 56 | 3 37 6 0.31 7591.03 57 | 32 101 5 0.284 9511.93 58 | 32 101 6 0.3 9187.27 59 | 32 101 7 0.291 8780.2 60 | 32 101 8 0.265 8352.78 61 | 32 101 9 0.317 7979.34 62 | 46 50 0 0.309 8300.39 63 | 46 50 2 0.249348 7927.25 64 | 46 50 3 0.304 7798.84 65 | 46 50 6 0.311 7598.79 66 | 46 50 7 0.286 7587.72 67 | 46 50 8 0.32 7590.56 68 | 46 50 9 0.304 7600.43 69 | 29 20 4 0.294 7979.03 70 | 29 20 5 0.293 7984.11 71 | 37 125 5 0.253 7440.66 72 | 37 125 6 0.297 7155.93 73 | 37 125 8 0.2196 6632.43 74 | 53 9 6 0.303 8542.37 75 | 53 9 7 0.309 8591.16 76 | 53 9 8 0.302 8641.07 77 | 35 93 4 0.299 7846.1 78 | 35 93 8 0.302 7319.58 79 | 35 93 9 0.302 7420.89 80 | 56 73 7 0.273 8148.86 81 | 56 73 8 0.3 8328.38 82 | 89 111 3 0.311062 7674.02 83 | 89 111 4 0.315 7547.67 84 | 89 111 5 0.282 7624.56 85 | 89 111 7 0.2689 8125.58 86 | 89 111 8 0.219 8384.55 87 | 72 39 8 0.281 8176.51 88 | 60 19 8 0.247353 8255.38 89 | 60 19 9 0.278498 8244.64 90 | 72 21 7 0.301 8126.25 91 | 48 116 0 0.31 10049.7 92 | 48 116 1 0.29 9900.57 93 | 48 116 7 0.281 9237.45 94 | 48 116 8 0.238 9216.65 95 | 36 36 0 0.299 7447.8 96 | 36 36 3 0.33 7080.18 97 | 36 36 4 0.245186 7017.52 98 | 36 36 5 0.274 7005.74 99 | 36 36 7 0.327 7039.45 100 | 36 36 8 0.305 7083.49 101 | 40 118 5 0.277 8636.83 102 | 40 118 6 0.303 8443.77 103 | 62 18 7 0.266696 8506.99 104 | 62 18 8 0.279174 8467.53 105 | 62 18 9 0.321009 8405.58 106 | 83 58 2 0.27 9086.49 107 | 83 58 3 0.256526 9211.44 108 | 83 58 4 0.29 9121.01 109 | 83 58 5 0.292 8861.71 110 | 98 61 3 0.31 8928.97 111 | 98 61 4 0.282 8803.22 112 | 98 61 6 0.287 8300.9 113 | 98 61 7 0.293 8181.74 114 | 98 61 8 0.295 8232.74 115 | 98 61 9 0.322 8416.4 116 | 44 122 0 0.314 9941.4 117 | 44 122 1 0.296 9905.26 118 | 44 122 6 0.313 9251.43 119 | 44 122 7 0.286 8936.84 120 | 44 122 8 0.267 8603.23 121 | 52 74 0 0.279 8572.27 122 | 52 74 1 0.302 8050.3 123 | 52 74 5 0.283 7255.43 124 | 52 74 7 0.291 7842.87 125 | 52 74 8 0.266 8253.02 126 | 62 32 0 0.31 9602.95 127 | 62 32 1 0.274 9485.01 128 | 45 115 0 0.298 9583.76 129 | 45 115 1 0.277 9495.1 130 | 45 115 7 0.289 8255.57 131 | 45 115 8 0.271 7917.43 132 | 38 65 0 0.319319 8453.76 133 | 38 65 1 0.252035 8134.39 134 | 38 65 2 0.27 8013.45 135 | 38 65 3 0.304 8052.85 136 | 38 65 6 0.295 8442.66 137 | 43 64 0 0.212 9506.34 138 | 43 64 1 0.29318 8988.82 139 | 92 22 1 0.265 8249.71 140 | 92 22 2 0.271 8306.45 141 | 92 22 3 0.293 8443.11 142 | 64 63 0 0.29 9277.46 143 | 51 79 0 0.271 7619.3 144 | 51 79 1 0.313 7428.38 145 | 51 79 2 0.267 7381.23 146 | 51 79 3 0.281 7483.69 147 | 62 87 5 0.264 8708.73 148 | 62 87 7 0.263 8484.8 149 | 62 87 8 0.324 8401.73 150 | 69 99 0 0.303 9125.36 151 | 69 99 1 0.299 8818.43 152 | 69 99 2 0.303 8541.81 153 | 69 99 7 0.267 8317.33 154 | 69 99 8 0.306 8583.93 155 | 37 87 4 0.304 8024.39 156 | 37 87 6 0.2567 8538.15 157 | 37 87 7 0.295 8637.14 158 | 37 87 8 0.287108 8517.08 159 | 37 87 9 0.2026 8168.67 160 | 80 108 4 0.314 8141.86 161 | 80 108 5 0.255 7925.11 162 | 80 108 6 0.223 7739.66 163 | 80 108 7 0.269 7644.8 164 | 80 108 8 0.281 7685.65 165 | 88 34 6 0.279 8374.12 166 | 88 34 7 0.23 8246.31 167 | 92 129 1 0.27 4784.17 168 | 92 129 2 0.28 4661.2 169 | 76 101 0 0.325 8320.91 170 | 76 101 4 0.327 8341.63 171 | 76 101 5 0.278 8298.95 172 | 76 101 7 0.272 8179.66 173 | 76 101 8 0.295 8110.41 174 | 54 127 8 0.304 4932.44 175 | 54 127 9 0.295 4659.97 176 | 55 11 7 0.323 8131.05 177 | 55 11 8 0.281 8139.31 178 | 20 111 5 0.287 8107.66 179 | 20 111 6 0.255 8016.58 180 | 20 111 7 0.291 7922.29 181 | 45 58 0 0.297 8943.3 182 | 45 58 1 0.272 8729.51 183 | 45 58 7 0.301 8013.96 184 | 45 58 8 0.305 7888.32 185 | 98 3 6 0.292 6034.04 186 | 98 3 7 0.315 6125.48 187 | 31 90 4 0.307 7767.38 188 | 31 90 5 0.2876 7708.25 189 | 31 90 6 0.282 7717.98 190 | 31 90 7 0.275 7826.09 191 | 31 90 8 0.274 8009.18 192 | 31 90 9 0.304 8245.58 193 | 16 16 3 0.272 9192.96 194 | 16 16 4 0.303 8819.69 195 | 16 16 6 0.294 8091.67 196 | 16 16 7 0.263 7820.5 197 | 16 16 8 0.293 7619.38 198 | 16 16 9 0.253 7497.54 199 | 39 87 6 0.285 8108.54 200 | 39 87 7 0.288 8299.14 201 | 39 87 8 0.263216 8447.09 202 | 39 87 9 0.2026 8474.82 203 | 9 25 1 0.248 8071.26 204 | 9 25 2 0.203 7910.3 205 | 9 25 3 0.261 7933.56 206 | 9 25 4 0.285 8101.5 207 | 9 25 6 0.3148 8494.28 208 | 9 25 7 0.240445 8607.51 209 | 68 116 0 0.298 9909.26 210 | 68 116 2 0.305 9611.1 211 | 68 116 3 0.286 9418.14 212 | 68 116 4 0.304 9212.23 213 | 68 116 5 0.268 8981.18 214 | 68 116 8 0.292 8279.81 215 | 68 116 9 0.29 8070.15 216 | 20 27 0 0.322 9138.23 217 | 20 27 6 0.280293 7673.04 218 | 20 27 7 0.287 7401.26 219 | 20 27 8 0.297 7212.3 220 | 20 27 9 0.285 7124.67 221 | 79 60 4 0.283 8783.73 222 | 79 60 5 0.297 8786.5 223 | 81 67 1 0.28 8184.15 224 | 81 67 2 0.286 8028.3 225 | 81 67 3 0.277 7927.88 226 | 84 81 1 0.264 9299.64 227 | 84 81 2 0.289 9364.56 228 | 84 81 3 0.252 9363.72 229 | 84 81 4 0.292 9263.49 230 | 84 81 6 0.266 8994.36 231 | 84 81 7 0.244 8927.14 232 | 84 81 9 0.315 9129.29 233 | 59 0 7 0.303 4275.54 234 | 59 0 8 0.297 4496.21 235 | 59 0 9 0.275 4835.24 236 | 52 68 0 0.282 8824.15 237 | 52 68 1 0.287 8486.62 238 | 52 68 6 0.272 7449.72 239 | 52 68 7 0.282 7486.73 240 | 52 68 8 0.271 7628.17 241 | 75 20 8 0.291 8316.43 242 | 68 3 8 0.283 5830.63 243 | 41 120 5 0.28 9068.96 244 | 41 120 6 0.299 8839.04 245 | 41 120 7 0.274 8583.58 246 | 41 120 8 0.287 8307.24 247 | 68 80 4 0.29 8675.53 248 | 68 80 5 0.298 8550.27 249 | 68 80 7 0.286739 8501.28 250 | 68 80 8 0.316 8554.87 251 | 84 109 4 0.317 7835.52 252 | 84 109 5 0.286 7812.89 253 | 84 109 7 0.268 8018.91 254 | 84 109 8 0.315416 8084.39 255 | 30 1 0 0.321 5035.61 256 | 30 1 1 0.261 4928.21 257 | 30 1 5 0.303 4969.39 258 | 30 1 7 0.294 5085.23 259 | 30 1 8 0.287 5143.28 260 | 30 1 9 0.309 5192.35 261 | 86 34 4 0.296 8468.2 262 | 86 34 5 0.28 8428.54 263 | 86 34 8 0.307 8263.97 264 | 86 34 9 0.305 8181.37 265 | 90 55 3 0.292 8478.72 266 | 90 55 4 0.286 8640.83 267 | 90 55 7 0.272 8368.76 268 | 90 55 8 0.281 8146.43 269 | 60 122 4 0.326 9369.36 270 | 60 122 5 0.291 9316.12 271 | 60 122 8 0.297 9066.02 272 | 60 122 9 0.307 8960.28 273 | 78 122 7 0.29 8564.21 274 | 78 122 8 0.283 8268.05 275 | 67 28 2 0.3 8871.32 276 | 67 28 3 0.266 8892.45 277 | 67 28 4 0.302 8951.12 278 | 10 31 1 0.291 9198.68 279 | 10 31 2 0.234014 8544.04 280 | 10 31 3 0.295 8081.45 281 | 10 31 4 0.269 7896.86 282 | 74 32 2 0.278 8007.92 283 | 74 32 3 0.282 7942.71 284 | 74 32 4 0.317 7916.4 285 | 74 32 7 0.298 8072.34 286 | 74 32 9 0.285 8191.75 287 | 0 96 1 0.265 9182.96 288 | 0 96 2 0.223 8978.56 289 | 0 96 5 0.313 8492.07 290 | 0 96 6 0.301 8402.85 291 | 74 115 0 0.345 9668.26 292 | 5 41 3 0.274 7287.93 293 | 5 41 4 0.277 7432.05 294 | 5 41 5 0.345 7673.74 295 | 5 41 6 0.307 7990.15 296 | 51 95 2 0.279 8744.21 297 | 51 95 3 0.312 8662.82 298 | 64 25 3 0.279 9397.96 299 | 64 25 4 0.287 9428.83 300 | 41 83 2 0.266 8132.49 301 | 41 83 3 0.276 8362.61 302 | 41 83 6 0.276 8603.27 303 | 41 83 7 0.285 8378.15 304 | 41 83 8 0.240802 8028.98 305 | 41 83 9 0.29394 7720.26 306 | 24 77 4 0.303 8729.31 307 | 24 77 7 0.29 9358.84 308 | 24 77 8 0.291 9146.72 309 | 24 77 9 0.305 8875.01 310 | 53 22 3 0.33 8586.03 311 | 53 22 4 0.281 8681.85 312 | 70 49 7 0.272 8345.86 313 | 70 49 8 0.29 8370.46 314 | 80 33 4 0.296 7994.96 315 | 80 33 5 0.305 8012.07 316 | 80 33 8 0.29 8337.05 317 | 80 33 9 0.281 8412.34 318 | 33 19 0 0.279 8982.54 319 | 33 19 1 0.288 8867.19 320 | 42 97 1 0.271 9343.83 321 | 42 97 3 0.297 9309.97 322 | 42 97 4 0.278 9291.72 323 | 42 97 6 0.3 9239.12 324 | 42 97 7 0.223 9179.86 325 | 42 97 8 0.305 9096.01 326 | 42 97 9 0.28 8980.67 327 | 70 85 7 0.231311 8626.31 328 | 70 85 8 0.311 8545.81 329 | 64 69 0 0.297 8375.26 330 | 80 89 1 0.297 9307.26 331 | 80 89 2 0.296 9174.17 332 | 80 89 3 0.262 9061.66 333 | 80 89 4 0.316 8892.72 334 | 80 89 8 0.288 8572.61 335 | 80 89 9 0.315 8688.37 336 | 61 37 0 0.307 8678.04 337 | 61 37 1 0.271 8521.73 338 | 36 28 3 0.302018 8940.49 339 | 36 28 4 0.240181 8869.73 340 | 36 28 5 0.278 8754.33 341 | 36 28 6 0.275 8606.94 342 | 36 28 7 0.287 8431.85 343 | 36 28 8 0.314 8223.01 344 | 3 124 1 0.269 8070.23 345 | 3 124 2 0.28 7585.63 346 | 3 124 3 0.324 7131.06 347 | 3 124 4 0.305 6817.26 348 | 18 28 0 0.308 9531.78 349 | 18 28 6 0.296 8417.17 350 | 18 28 7 0.296 7992.24 351 | 18 28 8 0.291 7666.12 352 | 18 28 9 0.277 7470.16 353 | 50 33 8 0.335 8042.93 354 | 50 33 9 0.295 7911.72 355 | 62 120 3 0.29 8854.06 356 | 62 120 4 0.314 8734.75 357 | 62 120 5 0.294 8611.35 358 | 62 120 8 0.285 8249.84 359 | 62 120 9 0.296 8136.65 360 | 20 19 0 0.311 8593.74 361 | 20 19 7 0.285 8554.47 362 | 62 35 0 0.311 8401.93 363 | 62 35 1 0.269 8311.08 364 | 32 118 6 0.284 8908.73 365 | 32 118 7 0.268 8850.56 366 | 35 110 5 0.2362 7933.57 367 | 35 110 6 0.295 7627.01 368 | 38 72 2 0.276 9116.65 369 | 38 72 3 0.302 8602.78 370 | 38 72 4 0.285 8266.71 371 | 38 72 5 0.272 8103.28 372 | 38 72 6 0.287 8088.67 373 | 38 72 8 0.267 8315.48 374 | 38 72 9 0.306 8496.93 375 | 98 59 1 0.278295 9279.01 376 | 98 59 2 0.263 8975.14 377 | 98 59 6 0.308 8922.35 378 | 98 59 7 0.287 8929.4 379 | 98 59 8 0.29 8637.96 380 | 98 59 9 0.329 8277.96 381 | 90 5 1 0.264 7961.78 382 | 90 5 2 0.255 7836.32 383 | 62 118 3 0.277 7955.32 384 | 62 118 4 0.294 7861.18 385 | 62 118 8 0.282 7663.57 386 | 62 118 9 0.288 7652.07 387 | 45 27 3 0.307 8643.22 388 | 45 27 4 0.296 8587.31 389 | 45 27 6 0.314 8658.52 390 | 45 27 7 0.304 8725.84 391 | 45 27 8 0.307 8777.91 392 | 45 27 9 0.28 8737.11 393 | 66 129 0 0.255436 4109.09 394 | 66 129 2 0.29 4020.74 395 | 66 129 3 0.272 3991.85 396 | 28 31 0 0.322 10089.9 397 | 28 31 7 0.31 7623.15 398 | 28 31 8 0.294 7369.93 399 | 28 31 9 0.273 7212.74 400 | 56 109 4 0.317 9658.38 401 | 56 109 8 0.299 9137.98 402 | 56 109 9 0.272 9037.13 403 | 51 101 0 0.294 9001.21 404 | 51 101 1 0.3 9086.22 405 | 51 101 8 0.233 9150.64 406 | 51 101 9 0.277 9012.86 407 | 60 19 8 0.29767 8255.38 408 | 60 19 9 0.319678 8244.64 409 | 28 121 5 0.28 8866.5 410 | 28 121 6 0.269 8750.33 411 | 28 121 7 0.279 8640.09 412 | 96 73 3 0.305 8647.23 413 | 96 73 4 0.273 8545.8 414 | 37 22 3 0.30599 8874.36 415 | 37 22 4 0.302029 8708.47 416 | 37 22 8 0.292 8282.58 417 | 37 22 9 0.298 8246.35 418 | 67 84 7 0.2522 8911.96 419 | 67 84 8 0.328 8951.28 420 | 23 47 1 0.262 9456.46 421 | 23 47 2 0.29 9414.33 422 | 23 47 7 0.29 7972.46 423 | 23 47 8 0.3 7757.01 424 | 23 47 9 0.279 7668.3 425 | 11 22 3 0.29 9104.48 426 | 11 22 4 0.271 8546.92 427 | 11 22 8 0.320762 7909.42 428 | 11 22 9 0.254 8138.57 429 | 28 44 1 0.322861 10082.2 430 | 28 44 2 0.2882 9474.45 431 | 28 44 5 0.268 8038.91 432 | 28 44 6 0.282 7748.93 433 | 28 44 7 0.3 7521.73 434 | 28 44 8 0.335 7340.23 435 | 28 44 9 0.299 7207 436 | 25 111 8 0.267766 7742.8 437 | 25 111 9 0.287 7588.25 438 | 11 86 6 0.303 9125.45 439 | 11 86 7 0.291 9019.7 440 | 64 61 0 0.273 9278.74 441 | 25 124 7 0.3 7560.25 442 | 99 118 1 0.26 8247.16 443 | 99 118 2 0.279 8114.22 444 | 99 118 3 0.276 8021.14 445 | 99 118 5 0.295 7988.47 446 | 99 118 6 0.319976 8028.86 447 | 99 118 7 0.262 8132.78 448 | 99 118 8 0.29 8253.17 449 | 99 118 9 0.3 8399.69 450 | 44 71 0 0.307888 8704.94 451 | 44 71 1 0.262425 8608.31 452 | 44 71 5 0.249423 7081.28 453 | 44 71 8 0.268 8672.05 454 | 44 71 9 0.316 9242.09 455 | 18 81 6 0.284 8844.8 456 | 18 81 7 0.3215 9026.47 457 | 30 120 4 0.308 9112.49 458 | 30 120 5 0.269 9064.29 459 | 30 120 6 0.282 9023.02 460 | 21 47 2 0.297 9102.39 461 | 21 47 8 0.307 7659.54 462 | 21 47 9 0.277 7556.62 463 | 87 22 2 0.233 8086.85 464 | 87 22 3 0.3 8002.55 465 | 40 106 7 0.27 8800.24 466 | 7 44 3 0.283 7451.31 467 | 7 44 4 0.285 7751.16 468 | 7 44 5 0.348 8154.19 469 | 7 44 6 0.301 8564.7 470 | 6 8 1 0.238 7857.01 471 | 6 8 3 0.255 7852.87 472 | 6 8 5 0.343 7884.17 473 | 6 8 6 0.286 7921.92 474 | 72 37 8 0.273 8026.72 475 | 69 74 4 0.283 8472.04 476 | 69 74 5 0.292 8481.62 477 | 88 37 4 0.2173 8179.23 478 | 88 37 5 0.265 7998.72 479 | 38 7 3 0.268 8558.02 480 | 38 7 4 0.326 8361.62 481 | 7 33 2 0.329555 7711.75 482 | 7 33 3 0.271 7885.03 483 | 7 33 4 0.29 8086.22 484 | 7 33 5 0.3537 8261.22 485 | 7 33 6 0.302 8379.26 486 | 52 110 0 0.281 8995.84 487 | 52 110 1 0.297 8970.69 488 | 52 110 3 0.312 9024.45 489 | 52 110 4 0.309 9079.29 490 | 52 110 7 0.265 9175.94 491 | 52 110 8 0.257 9119.89 492 | 63 121 3 0.279 7730.89 493 | 63 121 4 0.284 7737.66 494 | 63 121 5 0.294 7755.02 495 | 63 121 7 0.292 7867.93 496 | 63 121 8 0.3 7939.89 497 | 63 121 9 0.284 8009.09 498 | 83 10 2 0.271 8122.64 499 | 83 10 3 0.304 7580.92 500 | 47 50 1 0.301 7827.74 501 | 47 50 2 0.277 7734.37 502 | 47 50 3 0.303 7676.34 503 | 47 50 7 0.287 7551.77 504 | 47 50 8 0.308 7549.4 505 | 47 50 9 0.303 7551.22 506 | 40 56 2 0.24613 8266.91 507 | 40 56 3 0.313 8316.92 508 | 40 56 4 0.269 8349.25 509 | 25 82 3 0.29 9026.75 510 | 25 82 4 0.295 9221.46 511 | 50 129 6 0.306 3574.93 512 | 50 129 7 0.267 3437.91 513 | 77 4 5 0.287 7327.83 514 | 77 4 7 0.300803 7366.2 515 | 77 4 8 0.264 7298.16 516 | 32 118 6 0.284 8908.73 517 | 32 118 7 0.268 8850.56 518 | 69 60 0 0.294 8878.74 519 | 87 49 2 0.294 8529.37 520 | 87 49 3 0.278 8343.51 521 | 87 49 4 0.274 8293.27 522 | 87 49 5 0.2436 8386.41 523 | 87 49 7 0.273 8719.26 524 | 87 49 8 0.313 8789.96 525 | 85 95 6 0.269 7892.83 526 | 85 95 7 0.266 7954.7 527 | 99 22 2 0.268 9535.61 528 | 99 22 3 0.29 9552.95 529 | 99 22 8 0.303 8625.21 530 | 65 3 7 0.296 5840.84 531 | 65 3 8 0.286 5917.67 532 | 64 54 8 0.298 8312.09 533 | 42 56 2 0.206 8830.54 534 | 42 56 3 0.295 8559.09 535 | 42 56 4 0.27 8351 536 | 74 43 7 0.274 8940.05 537 | 74 43 8 0.266 8735.63 538 | 59 128 0 0.280152 5629.12 539 | 59 128 3 0.277 5232.28 540 | 59 128 4 0.304 5071.82 541 | 59 128 5 0.277 4903.77 542 | 59 128 8 0.296 4431.72 543 | 59 128 9 0.326 4306.03 544 | 86 47 3 0.278 9110.71 545 | 86 47 4 0.272 8889.78 546 | 86 47 5 0.275 8701.11 547 | 86 47 7 0.258 8530.71 548 | 86 47 8 0.32 8565.19 549 | 87 46 3 0.279 8845.98 550 | 87 46 4 0.287 8620.39 551 | 87 46 5 0.252 8483 552 | 87 46 7 0.261 8516.72 553 | 87 46 8 0.3191 8605.51 554 | 2 107 1 0.255 7885.89 555 | 2 107 2 0.247 7861.84 556 | 2 107 3 0.306 8042.91 557 | 2 107 4 0.297 8321.82 558 | 13 86 6 0.295 9177.9 559 | 13 86 7 0.304 9117.85 560 | 38 42 0 0.314 7939.35 561 | 38 42 2 0.255 7536.33 562 | 38 42 3 0.308 7393.58 563 | 38 42 4 0.28 7346.58 564 | 38 42 6 0.301 7347.4 565 | 38 42 7 0.326 7393.86 566 | 38 42 8 0.316 7476.39 567 | 38 42 9 0.32363 7558.92 568 | 54 81 0 0.301632 8609.49 569 | 54 81 4 0.240519 8167.01 570 | 54 81 5 0.25092 8152.33 571 | -------------------------------------------------------------------------------- /examples/data/tatitlek_815_mhhw_2011.nc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czwchenzhun/tfinterpy/9dc3b97260ec8b1d9d6631c33c3e19c298bb6f4a/examples/data/tatitlek_815_mhhw_2011.nc -------------------------------------------------------------------------------- /examples/gui/guiDemo.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.gui.tool import * 2 | 3 | if __name__ == '__main__': 4 | app = QApplication(sys.argv) 5 | exe = Tool() 6 | exe.showMaximized() 7 | sys.exit(app.exec_()) 8 | -------------------------------------------------------------------------------- /examples/ncFileUtil.py: -------------------------------------------------------------------------------- 1 | import netCDF4 as nc 2 | import random 3 | import numpy as np 4 | import os 5 | import os.path as op 6 | 7 | 8 | def getNCFileList(dirPath): 9 | ''' 10 | Returns all netcdf files' path under the specified directory. 11 | 12 | :param dirPath: str, directory. 13 | :return: list, files' path. 14 | ''' 15 | ls = [] 16 | if not op.exists(dirPath): 17 | return ls 18 | for file in os.listdir(dirPath): 19 | if file[-3:] == '.nc': 20 | ls.append(file) 21 | return ls 22 | 23 | 24 | def peakNCWH(filePath, wk="lon", hk="lat"): 25 | ''' 26 | Get the width and height information contained in the nc file. 27 | 28 | :param filePath: str. 29 | :param wk: str, the key corresponding to the width. 30 | :param hk: str, the key corresponding to the height. 31 | :return: tuple, (width, height). 32 | If the file does not contain width and height information, 33 | return (None,None). 34 | ''' 35 | if not op.exists(filePath): 36 | return None, None 37 | try: 38 | dem = nc.Dataset(filePath) 39 | except: 40 | print("netcdf 文件读取异常") 41 | return None, None 42 | W = dem.dimensions[wk].size 43 | H = dem.dimensions[hk].size 44 | dem.close() 45 | return W, H 46 | 47 | 48 | def peakNCInfo(filePath): 49 | ''' 50 | Get the key and corresponding shape information contained in the nc file. 51 | 52 | :param filePath: str. 53 | :return: tuple, (keys,info). 54 | keys is list containing all key in nc file. 55 | info is a string that records the shape of the variables. 56 | ''' 57 | if not op.exists(filePath): 58 | return None, None 59 | try: 60 | dem = nc.Dataset(filePath) 61 | except: 62 | print("netcdf 文件读取异常") 63 | return None, None 64 | info = '' 65 | keys = [] 66 | for key in dem.variables.keys(): 67 | if dem.variables[key].shape == (): 68 | continue 69 | keys.append(key) 70 | info += "%s shape: %s\n" % (key, str(dem.variables[key].shape)) 71 | dem.close() 72 | return keys, info 73 | 74 | 75 | def getSamples(filePathOrData, X, Y, Z, begin=(0, 0), sub=(200, 200), N=10): 76 | ''' 77 | :param filePath: str. 78 | :param X: str, key of lats. 79 | :param Y: str, key of lons. 80 | :param Z: str, key of ele. 81 | :param begin: tuple, the begining index of the submap. 82 | :param sub: tuple, the size of the submap. 83 | :param N: integer, number of samples in X and Y directions. 84 | :return: tuple, (samples,lats,lons,ele). 85 | samples is the sampling point obtained by random sampling within the submap. 86 | lats is latitude of submap. 87 | lons is longitude of submap. 88 | ele is elevation of submap. 89 | ''' 90 | if type(filePathOrData) == type(''): 91 | dem = nc.Dataset(filePathOrData) 92 | data = dem.variables 93 | else: 94 | data = filePathOrData 95 | by, bx = begin 96 | suby, subx = sub 97 | lats = data[X][bx:bx + subx] # 纬度值 98 | lons = data[Y][by:by + suby] # 经度值 99 | ele = data[Z][bx:bx + subx, by:by + suby] # 海拔值 100 | if type(filePathOrData) == type(''): 101 | dem.close() # 102 | subx, suby = sub 103 | samples = [] 104 | c = 0 105 | while c < N: 106 | x = random.randint(0, subx - 1) 107 | y = random.randint(0, suby - 1) 108 | if [x, y, ele[y, x]] not in samples: 109 | samples.append([x, y, ele[y, x]]) 110 | c += 1 111 | samples = np.array(samples, dtype="float32") 112 | return samples, lats, lons, ele 113 | -------------------------------------------------------------------------------- /examples/nestVariogram.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | from tfinterpy.variogram import calculateOmnidirectionalVariogram2D 3 | from ncFileUtil import getSamples 4 | from tfinterpy.utils import calcVecs 5 | 6 | if __name__ == "__main__": 7 | filePath = "data/tatitlek_815_mhhw_2011.nc" 8 | W, H = 200, 200 9 | M = 100 10 | offset = (100, 100) 11 | 12 | # Get sample points and original elevation data from netcdf file 13 | # containing Digital Elevation Model data. 14 | samples, lats, lons, ele = getSamples(filePath, 'lat', 'lon', 'Band1', offset, (W, H), M) 15 | 16 | # Calculate the nested variogram function. 17 | nestVariogram, variogramBuilders = calculateOmnidirectionalVariogram2D(samples) 18 | for vb in variogramBuilders: 19 | plt.figure() 20 | vb.showVariogram() 21 | plt.show() 22 | -------------------------------------------------------------------------------- /examples/plotUtils.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | 3 | plt.rcParams['font.sans-serif'] = ['SimHei'] 4 | plt.rcParams['axes.unicode_minus'] = False 5 | 6 | 7 | def img2d(data, xlabel="lons", ylabel="lats", title="", vmin=None, vmax=None): 8 | ''' 9 | Plotting 2d data as image. 10 | 11 | :param data: ndarray, 2d data. 12 | :param xlabel: str. 13 | :param ylabel: str. 14 | :param title: str. 15 | :param vmin: number. 16 | :param vmax: number. 17 | :return: None. 18 | ''' 19 | if title != "": 20 | plt.title(title) 21 | plt.imshow(data, cmap="rainbow", vmin=vmin, vmax=vmax) 22 | ax = plt.gca() 23 | ax.set_xlabel(xlabel) 24 | ax.get_xaxis().get_major_formatter().set_scientific(False) 25 | ax.set_ylabel(ylabel) 26 | ax.get_yaxis().get_major_formatter().set_scientific(False) 27 | plt.colorbar() 28 | 29 | 30 | def scatter2d(data, xidx=0, yidx=1, zidx=-1, axes=None, xlabel="lons", ylabel="lats", title=""): 31 | ''' 32 | Plotting 2d scatter. 33 | 34 | :param data: ndarray, points data. 35 | :param xidx: integer, index of x coordinate. 36 | :param yidx: integer, index of y coordinate. 37 | :param zidx: integer, index of property. 38 | :param axes: matplotlib axes. 39 | :param xlabel: str. 40 | :param ylabel: str. 41 | :param title: str. 42 | :return: matplotlib.collections.PathCollection object. 43 | ''' 44 | if title != "": 45 | plt.title(title) 46 | if axes is None: 47 | if zidx >= 0: 48 | scatter = plt.scatter(data[:, xidx], data[:, yidx], s=data[:, zidx], alpha=0.5) 49 | else: 50 | scatter = plt.scatter(data[:, xidx], data[:, yidx], alpha=0.5) 51 | else: 52 | if zidx >= 0: 53 | scatter = axes.scatter(data[:, xidx], data[:, yidx], s=data[:, zidx], alpha=0.5) 54 | else: 55 | scatter = axes.scatter(data[:, xidx], data[:, yidx], alpha=0.5) 56 | ax = plt.gca() 57 | ax.set_xlabel(xlabel) 58 | ax.get_xaxis().get_major_formatter().set_scientific(False) 59 | ax.set_ylabel(ylabel) 60 | ax.get_yaxis().get_major_formatter().set_scientific(False) 61 | return scatter 62 | 63 | 64 | def scatter3d(data, axes=None, xlabel='h', ylabel='angle', zlabel='var', alpha=0.5, title=""): 65 | ''' 66 | Plotting 3d scatter. 67 | 68 | :param data: ndarray, points data. 69 | :param axes: matplotlib axes. 70 | :param xlabel: str. 71 | :param ylabel: str. 72 | :param zlabel: str. 73 | :param alpha: number. 74 | :param title: str. 75 | :return: matplotlib.axes._subplots.Axes3DSubplot object. 76 | ''' 77 | if title != "": 78 | plt.title(title) 79 | if axes is None: 80 | axes = plt.axes(projection='3d') 81 | X, Y, Z = data[:, 0], data[:, 1], data[:, 2] 82 | scatter = axes.scatter(X, Y, Z, alpha=alpha) 83 | axes.set_xlabel(xlabel) 84 | axes.set_ylabel(ylabel) 85 | axes.set_zlabel(zlabel) 86 | return scatter 87 | -------------------------------------------------------------------------------- /examples/temperature.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.krige import OK 2 | from plotUtils import * 3 | from tfinterpy.variogram import calculateOmnidirectionalVariogram2D 4 | from tfinterpy.utils import calcVecs 5 | import pandas as pd 6 | 7 | if __name__ == '__main__': 8 | df = pd.read_csv("data/AustraliaTemperature20210101.csv") 9 | samples = df[["LONGITUDE", "LATITUDE", "TEMP"]].values 10 | 11 | nv, vbs = calculateOmnidirectionalVariogram2D(samples, model=None) 12 | for vb in vbs: 13 | plt.figure() 14 | vb.showVariogram() 15 | plt.show() 16 | N = 8 17 | exe = OK(samples) 18 | print(exe.crossValidate(N, nv)) 19 | print(exe.crossValidateKFold(10, N, nv)) 20 | -------------------------------------------------------------------------------- /examples/tf/IDW2D.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.tf.idw import TFIDW 2 | from tfinterpy.grid import Grid2D 3 | from ncFileUtil import getSamples 4 | from plotUtils import * 5 | import numpy as np 6 | import tensorflow as tf 7 | import random 8 | 9 | if __name__ == "__main__": 10 | print(tf.config.experimental.list_physical_devices('CPU')) # Prints all CPU devices. 11 | print(tf.config.experimental.list_physical_devices('GPU')) # Prints all GPU devices. 12 | 13 | random.seed(1) 14 | W, H = 100, 100 15 | M = 100 16 | offset = (400, 800) 17 | N = 8 18 | 19 | # Get sample points and original elevation data from netcdf file 20 | # containing Digital Elevation Model data. 21 | samples, lats, lons, ele = getSamples("data/tatitlek_815_mhhw_2011.nc", 'lat', 'lon', 'Band1', 22 | offset, (W, H), M) 23 | # Create linear 2D grid. 24 | grid = Grid2D() 25 | grid.rectlinear((W, H), (1, W), (1, H)) 26 | 27 | exe = TFIDW(samples)# Create a idw(tensorflow version) interpolator. 28 | 29 | # Specify the GPU to be used. 30 | with tf.device("/GPU:0"): 31 | # Perform interpolation of all points in the grid. 32 | grid.pro = exe.execute(grid.points(), N) 33 | 34 | print(exe.crossValidate(N))# Perform leave-one-out validation and print result. 35 | print(exe.crossValidateKFold(10, N))# Perform k-fold validation and print result. 36 | 37 | pro = grid.pro.reshape((grid.dim[1], grid.dim[0]))# Reshape properties as 2d ndarray. 38 | plt.figure() 39 | plt.subplot(221) 40 | img2d(ele, title="origin")# Plotting original elevation data. 41 | plt.subplot(222) 42 | img2d(pro, title="estimate")# Plotting interpolation results. 43 | absdiff = np.abs(pro - ele) 44 | plt.subplot(223) 45 | img2d(absdiff, title="error")# Plotting absolute errors. 46 | print('result MAE:', np.mean(absdiff)) 47 | plt.show() 48 | -------------------------------------------------------------------------------- /examples/tf/IDW3D.py: -------------------------------------------------------------------------------- 1 | import tfinterpy.vtk.colorMap as CM 2 | from tfinterpy.vtk.rendering import createGridActor, rendering 3 | from tfinterpy.vtk.fileUtils import saveVTKGrid 4 | from tfinterpy.tf.idw import TFIDW 5 | from tfinterpy.grid import Grid3D 6 | from tfinterpy.gslib.fileUtils import readGslibPoints 7 | import tensorflow as tf 8 | 9 | if __name__ == "__main__": 10 | print(tf.config.experimental.list_physical_devices('CPU')) # Prints all CPU devices. 11 | print(tf.config.experimental.list_physical_devices('GPU')) # Prints all GPU devices. 12 | 13 | filePath = "data/sample_data.gslib" 14 | N = 8 15 | df = readGslibPoints(filePath)# Read 3d points from gslib file. 16 | print(df.describe()) 17 | samples = df[['x', 'y', 'z', 'porosity']].values 18 | 19 | # Create linear 3D grid. 20 | grid = Grid3D() 21 | grid.rectlinear((100, 100, 10), (samples[:, 0].min(), samples[:, 0].max()), 22 | (samples[:, 1].min(), samples[:, 1].max()), (samples[:, 2].min(), samples[:, 2].max())) 23 | exe = TFIDW(samples, '3d')# Create a idw interpolator. 24 | 25 | # Specify the GPU to be used. 26 | with tf.device("/GPU:0"): 27 | # Perform interpolation of all points in the grid. 28 | grid.pro = exe.execute(grid.points(), N) 29 | 30 | print(exe.crossValidate(N))# Perform leave-one-out validation and print result. 31 | print(exe.crossValidateKFold(10, N))# Perform k-fold validation and print result. 32 | 33 | # Create an actor representing a rectilinear grid and use the interpolation results for color mapping. 34 | actor = createGridActor(*grid.dim, grid.x, grid.y, grid.z, grid.pro, 35 | [samples[:, 3].min(), samples[:, 3].max()], CM.Rainbow) 36 | rendering(actor)# Rendering vtkActor. 37 | saveVTKGrid('savedData/grid.vtk', actor.GetMapper().GetInput())# Save grid data to vtk file. 38 | -------------------------------------------------------------------------------- /examples/tf/OK2D.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.tf.krige import TFOK 2 | from tfinterpy.grid import Grid2D 3 | import tensorflow as tf 4 | from ncFileUtil import getSamples 5 | from plotUtils import * 6 | import numpy as np 7 | from tfinterpy.variogram import calculateDefaultVariogram2D 8 | from tfinterpy.tf.variogramLayer import getVariogramLayer 9 | import random 10 | 11 | if __name__ == "__main__": 12 | print(tf.config.experimental.list_physical_devices('CPU')) # Prints all CPU devices. 13 | print(tf.config.experimental.list_physical_devices('GPU')) # Prints all GPU devices. 14 | 15 | random.seed(1) 16 | W, H = 200, 200 17 | M = 100 18 | offset = (100, 300) 19 | N = 8 20 | 21 | # Get sample points and original elevation data from netcdf file 22 | # containing Digital Elevation Model data. 23 | samples, lats, lons, ele = getSamples("data/tatitlek_815_mhhw_2011.nc", 'lat', 'lon', 'Band1', 24 | offset, (W, H), M) 25 | 26 | # Create linear 2D grid. 27 | grid = Grid2D() 28 | grid.rectlinear((W, H), (1, W), (1, H)) 29 | 30 | # Calculate a default variogram function. 31 | vb = calculateDefaultVariogram2D(samples) 32 | plt.figure() 33 | vb.showVariogram() 34 | plt.show() 35 | vl = getVariogramLayer(vb)#Create variogram layer by variogram builder. 36 | 37 | exe = TFOK(samples)# Create a ok(tensorflow version) interpolator. 38 | 39 | # Specify the GPU to be used. 40 | with tf.device("/GPU:0"): 41 | # Perform interpolation of all points in the grid. 42 | grid.pro, grid.sigma = exe.execute(grid.points(), N, vl, 1000) 43 | 44 | print(exe.crossValidateKFold(10, N, vl))# Perform k-fold validation and print result. 45 | print(exe.crossValidate(N, vl))# Perform leave-one-out validation and print result. 46 | 47 | pro = grid.pro.reshape((grid.dim[1], grid.dim[0]))# Reshape properties as 2d ndarray. 48 | sigma = grid.sigma.reshape((grid.dim[1], grid.dim[0]))# Reshape kriging variances as 2d ndarray. 49 | plt.figure(figsize=(8, 8)) 50 | plt.subplot(221) 51 | img2d(ele, title="origin")# Plotting original elevation data. 52 | plt.subplot(222) 53 | img2d(pro, title="estimate")# Plotting interpolation results. 54 | absdiff = np.abs(pro - ele) 55 | plt.subplot(223) 56 | img2d(absdiff, title="error")# Plotting absolute errors. 57 | print('result MAE:', np.mean(absdiff)) 58 | plt.subplot(224) 59 | img2d(sigma, title="krige variance")# Plotting kriging variances. 60 | plt.show() 61 | -------------------------------------------------------------------------------- /examples/tf/OK2DWithNestVariogram.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.tf.krige import TFOK 2 | from tfinterpy.grid import Grid2D 3 | import tensorflow as tf 4 | from ncFileUtil import getSamples 5 | from plotUtils import * 6 | import numpy as np 7 | from tfinterpy.utils import calcVecs 8 | from tfinterpy.variogram import calculateOmnidirectionalVariogram2D 9 | from tfinterpy.tf.variogramLayer import getNestVariogramLayer 10 | import random 11 | 12 | if __name__ == "__main__": 13 | print(tf.config.experimental.list_physical_devices('CPU')) # Prints all CPU devices. 14 | print(tf.config.experimental.list_physical_devices('GPU')) # Prints all GPU devices. 15 | 16 | random.seed(1) 17 | W, H = 200, 200 18 | M = 100 19 | offset = (200, 0) 20 | N = 8 21 | 22 | # Get sample points and original elevation data from netcdf file 23 | # containing Digital Elevation Model data. 24 | samples, lats, lons, ele = getSamples("data/tatitlek_815_mhhw_2011.nc", 'lat', 'lon', 'Band1', 25 | offset, (W, H), M) 26 | 27 | # Create linear 2D grid. 28 | grid = Grid2D() 29 | grid.rectlinear((W, H), (1, W), (1, H)) 30 | 31 | # Calculate nested variation function. 32 | nestVariogram, variogramBuilders = calculateOmnidirectionalVariogram2D(samples) 33 | # Get nested variation function layer. 34 | nestVariogramLayer = getNestVariogramLayer(variogramBuilders, nestVariogram.unitVectors) 35 | 36 | exe = TFOK(samples)# Create a ok(tensorflow version) interpolator. 37 | 38 | # Specify the GPU to be used. 39 | with tf.device("/GPU:0"): 40 | # Perform interpolation of all points in the grid. 41 | grid.pro, grid.sigma = exe.execute(grid.points(), N, nestVariogramLayer, 10000) 42 | 43 | print(exe.crossValidateKFold(10, N, nestVariogramLayer))# Perform k-fold validation and print result. 44 | print(exe.crossValidate(N, nestVariogramLayer))# Perform leave-one-out validation and print result. 45 | 46 | pro = grid.pro.reshape((grid.dim[1], grid.dim[0]))# Reshape properties as 2d ndarray. 47 | sigma = grid.sigma.reshape((grid.dim[1], grid.dim[0]))# Reshape kriging variances as 2d ndarray. 48 | plt.figure(figsize=(8, 8)) 49 | plt.subplot(221) 50 | img2d(ele, title="origin")# Plotting original elevation data. 51 | plt.subplot(222) 52 | img2d(pro, title="estimate")# Plotting interpolation results. 53 | absdiff = np.abs(pro - ele) 54 | plt.subplot(223) 55 | img2d(absdiff, title="error")# Plotting absolute errors. 56 | print('result MAE:', np.mean(absdiff)) 57 | plt.subplot(224) 58 | img2d(sigma, title="krige variance")# Plotting kriging variances. 59 | plt.show() 60 | -------------------------------------------------------------------------------- /examples/tf/OK3D.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.variogram import calculateDefaultVariogram3D 2 | from tfinterpy.gslib.fileUtils import readGslibPoints 3 | from tfinterpy.vtk.rendering import createGridActor, rendering 4 | import tfinterpy.vtk.colorMap as CM 5 | from tfinterpy.vtk.fileUtils import saveVTKGrid 6 | # import vtk dependencies first 7 | from tfinterpy.tf.variogramLayer import getVariogramLayer 8 | from tfinterpy.tf.krige import TFOK 9 | from tfinterpy.grid import Grid3D 10 | import matplotlib.pyplot as plt 11 | import tensorflow as tf 12 | 13 | if __name__ == "__main__": 14 | print(tf.config.experimental.list_physical_devices('CPU')) # Prints all CPU devices. 15 | print(tf.config.experimental.list_physical_devices('GPU')) # Prints all GPU devices. 16 | 17 | filePath = "data/sample_data.gslib" 18 | N = 8 19 | df = readGslibPoints(filePath)# Read 3d points from gslib file. 20 | print(df.describe()) 21 | samples = df[['x', 'y', 'z', 'porosity']].values 22 | 23 | # Create linear 3D grid. 24 | grid = Grid3D() 25 | grid.rectlinear((100, 100, 10), (samples[:, 0].min(), samples[:, 0].max()), 26 | (samples[:, 1].min(), samples[:, 1].max()), (samples[:, 2].min(), samples[:, 2].max())) 27 | 28 | # Calculate a default variogram function. 29 | vb = calculateDefaultVariogram3D(samples) 30 | plt.figure() 31 | vb.showVariogram() 32 | plt.show() 33 | vl = getVariogramLayer(vb)#Create variogram layer by variogram builder. 34 | 35 | exe = TFOK(samples, '3d')# Create a ok(tensorflow version) interpolator. 36 | 37 | # Specify the GPU to be used. 38 | with tf.device("/GPU:0"): 39 | # Perform interpolation of all points in the grid. 40 | grid.pro, grid.sigma = exe.execute(grid.points(), N, vl, 1000) 41 | 42 | # Create an actor representing a rectilinear grid and use the interpolation results for color mapping. 43 | actor = createGridActor(*grid.dim, grid.x, grid.y, grid.z, grid.pro, 44 | [samples[:, 3].min(), samples[:, 3].max()], CM.Rainbow) 45 | rendering(actor)# Rendering vtkActor. 46 | # Create an actor representing a rectilinear grid and use the kriging variances for color mapping. 47 | actor = createGridActor(*grid.dim, grid.x, grid.y, grid.z, grid.sigma, None, CM.Rainbow) 48 | rendering(actor)# Rendering vtkActor. 49 | saveVTKGrid('savedData/grid.vtk', actor.GetMapper().GetInput())# Save grid data(kriging variances) to vtk file. 50 | -------------------------------------------------------------------------------- /examples/tf/OK3DWithNestVariogram.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.variogram import calculateOmnidirectionalVariogram3D 2 | from tfinterpy.gslib.fileUtils import readGslibPoints 3 | from tfinterpy.vtk.rendering import createGridActor, rendering 4 | import tfinterpy.vtk.colorMap as CM 5 | from tfinterpy.vtk.fileUtils import saveVTKGrid 6 | # import vtk dependencies first 7 | from tfinterpy.tf.variogramLayer import getNestVariogramLayer 8 | from tfinterpy.tf.krige import TFOK 9 | from tfinterpy.grid import Grid3D 10 | from tfinterpy.utils import calcVecs 11 | import matplotlib.pyplot as plt 12 | import tensorflow as tf 13 | 14 | 15 | if __name__ == "__main__": 16 | print(tf.config.experimental.list_physical_devices('CPU')) # Prints all CPU devices. 17 | print(tf.config.experimental.list_physical_devices('GPU')) # Prints all GPU devices. 18 | 19 | filePath = "data/sample_data.gslib" 20 | N = 8 21 | df = readGslibPoints(filePath)# Read 3d points from gslib file. 22 | print(df.describe()) 23 | samples = df[['x', 'y', 'z', 'porosity']].values 24 | 25 | # Create linear 3D grid. 26 | grid = Grid3D() 27 | grid.rectlinear((100, 100, 10), (samples[:, 0].min(), samples[:, 0].max()), 28 | (samples[:, 1].min(), samples[:, 1].max()), (samples[:, 2].min(), samples[:, 2].max())) 29 | 30 | # Calculate nested variation function. 31 | nestVariogram, variogramBuilders = calculateOmnidirectionalVariogram3D(samples, [5, 5]) 32 | for vb in variogramBuilders: 33 | plt.figure() 34 | vb.showVariogram() 35 | plt.show() 36 | # Get nested variation function layer. 37 | vl = getNestVariogramLayer(variogramBuilders, nestVariogram.unitVectors) 38 | 39 | exe = TFOK(samples, '3d')# Create a ok(tensorflow version) interpolator. 40 | # Specify the GPU to be used. 41 | with tf.device("/CPU:0"): 42 | # Perform interpolation of all points in the grid. 43 | grid.pro, grid.sigma = exe.execute(grid.points(), N, vl, batch_size=10000) 44 | 45 | print(exe.crossValidateKFold(10, N, vl))# Perform k-fold validation and print result. 46 | print(exe.crossValidate(N, vl))# Perform leave-one-out validation and print result. 47 | 48 | # Create an actor representing a rectilinear grid and use the interpolation results for color mapping. 49 | actor = createGridActor(*grid.dim, grid.x, grid.y, grid.z, grid.pro, [samples[:, 3].min(), samples[:, 3].max()], 50 | CM.Rainbow) 51 | rendering(actor)# Rendering vtkActor. 52 | # Create an actor representing a rectilinear grid and use the kriging variances for color mapping. 53 | actor = createGridActor(*grid.dim, grid.x, grid.y, grid.z, grid.sigma, None, CM.Rainbow) 54 | rendering(actor)# Rendering vtkActor. 55 | saveVTKGrid('savedData/grid.vtk', actor.GetMapper().GetInput())# Save grid data(kriging variances) to vtk file. 56 | -------------------------------------------------------------------------------- /examples/tf/SK2D.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.tf.krige import TFSK 2 | from tfinterpy.grid import Grid2D 3 | from ncFileUtil import getSamples 4 | from plotUtils import * 5 | import numpy as np 6 | import tensorflow as tf 7 | from tfinterpy.variogram import calculateDefaultVariogram2D 8 | from tfinterpy.tf.variogramLayer import getVariogramLayer 9 | import random 10 | 11 | if __name__ == "__main__": 12 | print(tf.config.experimental.list_physical_devices('CPU')) # Prints all CPU devices. 13 | print(tf.config.experimental.list_physical_devices('GPU')) # Prints all GPU devices. 14 | 15 | random.seed(1) 16 | W, H = 100, 100 17 | M = 100 18 | offset = (400, 800) 19 | N = 8 20 | 21 | # Get sample points and original elevation data from netcdf file 22 | # containing Digital Elevation Model data. 23 | samples, lats, lons, ele = getSamples("data/tatitlek_815_mhhw_2011.nc", 'lat', 'lon', 'Band1', 24 | offset, (W, H), M) 25 | 26 | # Create linear 2D grid. 27 | grid = Grid2D() 28 | grid.rectlinear((W, H), (1, W), (1, H)) 29 | 30 | # Calculate a default variogram function. 31 | vb = calculateDefaultVariogram2D(samples) 32 | plt.figure() 33 | vb.showVariogram() 34 | plt.show() 35 | vl = getVariogramLayer(vb)#Create variogram layer by variogram builder. 36 | 37 | exe = TFSK(samples)# Create a sk(tensorflow version) interpolator. 38 | 39 | # Specify the GPU to be used. 40 | with tf.device("/GPU:0"): 41 | # Perform interpolation of all points in the grid. 42 | grid.pro, grid.sigma = exe.execute(grid.points(), N, vl, 1000) 43 | 44 | print(exe.crossValidateKFold(10, N, vl))# Perform k-fold validation and print result. 45 | print(exe.crossValidate(N, vl))# Perform leave-one-out validation and print result. 46 | 47 | pro = grid.pro.reshape((grid.dim[1], grid.dim[0]))# Reshape properties as 2d ndarray. 48 | sigma = grid.sigma.reshape((grid.dim[1], grid.dim[0]))# Reshape kriging variances as 2d ndarray. 49 | plt.figure(figsize=(8, 8)) 50 | plt.subplot(221) 51 | img2d(ele, title="origin")# Plotting original elevation data. 52 | plt.subplot(222) 53 | img2d(pro, title="estimate")# Plotting interpolation results. 54 | absdiff = np.abs(pro - ele) 55 | plt.subplot(223) 56 | img2d(absdiff, title="error")# Plotting absolute errors. 57 | print('result MAE:', np.mean(absdiff)) 58 | plt.subplot(224) 59 | img2d(sigma, title="krige variance")# Plotting kriging variances. 60 | plt.show() 61 | -------------------------------------------------------------------------------- /examples/tf/SK2DWithNestVariogram.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.tf.krige import TFSK 2 | from tfinterpy.grid import Grid2D 3 | from ncFileUtil import getSamples 4 | from plotUtils import * 5 | import numpy as np 6 | import tensorflow as tf 7 | from tfinterpy.utils import calcVecs 8 | from tfinterpy.variogram import calculateOmnidirectionalVariogram2D 9 | from tfinterpy.tf.variogramLayer import getNestVariogramLayer 10 | import random 11 | 12 | if __name__ == "__main__": 13 | print(tf.config.experimental.list_physical_devices('CPU')) # Prints all CPU devices. 14 | print(tf.config.experimental.list_physical_devices('GPU')) # Prints all GPU devices. 15 | 16 | random.seed(1) 17 | W, H = 100, 100 18 | M = 100 19 | offset = (400, 800) 20 | N = 8 21 | 22 | # Get sample points and original elevation data from netcdf file 23 | # containing Digital Elevation Model data. 24 | samples, lats, lons, ele = getSamples("data/tatitlek_815_mhhw_2011.nc", 'lat', 'lon', 'Band1', 25 | offset, (W, H), M) 26 | 27 | # Create linear 2D grid. 28 | grid = Grid2D() 29 | grid.rectlinear((W, H), (1, W), (1, H)) 30 | 31 | # Calculate nested variation function. 32 | nestVariogram, variogramBuilders = calculateOmnidirectionalVariogram2D(samples) 33 | # Get nested variation function layer. 34 | nestVariogramLayer = getNestVariogramLayer(variogramBuilders, nestVariogram.unitVectors) 35 | 36 | exe = TFSK(samples)# Create a sk(tensorflow version) interpolator 37 | 38 | # Specify the GPU to be used. 39 | with tf.device("/GPU:0"): 40 | # Perform interpolation of all points in the grid. 41 | grid.pro, grid.sigma = exe.execute(grid.points(), N, nestVariogramLayer, 1000) 42 | 43 | print(exe.crossValidateKFold(10, N, nestVariogramLayer))# Perform k-fold validation and print result. 44 | print(exe.crossValidate(N, nestVariogramLayer))# Perform leave-one-out validation and print result. 45 | 46 | pro = grid.pro.reshape((grid.dim[1], grid.dim[0]))# Reshape properties as 2d ndarray. 47 | sigma = grid.sigma.reshape((grid.dim[1], grid.dim[0]))# Reshape kriging variances as 2d ndarray. 48 | plt.figure(figsize=(8, 8)) 49 | plt.subplot(221) 50 | img2d(ele, title="origin")# Plotting original elevation data. 51 | plt.subplot(222) 52 | img2d(pro, title="estimate")# Plotting interpolation results. 53 | absdiff = np.abs(pro - ele) 54 | plt.subplot(223) 55 | img2d(absdiff, title="error")# Plotting absolute errors. 56 | print('result MAE:', np.mean(absdiff)) 57 | plt.subplot(224) 58 | img2d(sigma, title="krige variance")# Plotting kriging variances. 59 | plt.show() 60 | -------------------------------------------------------------------------------- /examples/tf/SK3D.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.variogram import calculateDefaultVariogram3D 2 | from tfinterpy.gslib.fileUtils import readGslibPoints 3 | from tfinterpy.vtk.rendering import createGridActor, rendering 4 | import tfinterpy.vtk.colorMap as CM 5 | from tfinterpy.vtk.fileUtils import saveVTKGrid 6 | # import vtk dependencies first 7 | from tfinterpy.tf.variogramLayer import getVariogramLayer 8 | from tfinterpy.tf.krige import TFSK 9 | from tfinterpy.grid import Grid3D 10 | import matplotlib.pyplot as plt 11 | import tensorflow as tf 12 | 13 | if __name__ == "__main__": 14 | print(tf.config.experimental.list_physical_devices('CPU')) # Prints all CPU devices. 15 | print(tf.config.experimental.list_physical_devices('GPU')) # Prints all GPU devices. 16 | 17 | filePath = "data/sample_data.gslib" 18 | N = 8 19 | df = readGslibPoints(filePath)# Read 3d points from gslib file. 20 | print(df.describe()) 21 | samples = df[['x', 'y', 'z', 'porosity']].values 22 | 23 | # Create linear 3D grid. 24 | grid = Grid3D() 25 | grid.rectlinear((100, 100, 10), (samples[:, 0].min(), samples[:, 0].max()), 26 | (samples[:, 1].min(), samples[:, 1].max()), (samples[:, 2].min(), samples[:, 2].max())) 27 | 28 | # Calculate a default variogram function. 29 | vb = calculateDefaultVariogram3D(samples) 30 | plt.figure() 31 | vb.showVariogram() 32 | plt.show() 33 | vl = getVariogramLayer(vb)#Create variogram layer by variogram builder. 34 | 35 | exe = TFSK(samples, '3d')# Create a sk(tensorflow version) interpolator. 36 | 37 | # Specify the GPU to be used. 38 | with tf.device("/GPU:0"): 39 | # Perform interpolation of all points in the grid. 40 | grid.pro, grid.sigma = exe.execute(grid.points(), N, vl, 1000) 41 | 42 | print(exe.crossValidateKFold(10, N, vl))# Perform leave-one-out validation and print result. 43 | print(exe.crossValidate(N, vl))# Perform k-fold validation and print result. 44 | 45 | # Create an actor representing a rectilinear grid and use the interpolation results for color mapping. 46 | actor = createGridActor(*grid.dim, grid.x, grid.y, grid.z, grid.pro, [samples[:, 3].min(), samples[:, 3].max()], 47 | CM.Rainbow) 48 | rendering(actor)# Rendering vtkActor. 49 | # Create an actor representing a rectilinear grid and use the kriging variances for color mapping. 50 | actor = createGridActor(*grid.dim, grid.x, grid.y, grid.z, grid.sigma, None, CM.Rainbow) 51 | rendering(actor)# Rendering vtkActor. 52 | saveVTKGrid('savedData/grid.vtk', actor.GetMapper().GetInput())# Save grid data(kriging variances) to vtk file. 53 | -------------------------------------------------------------------------------- /examples/tf/SK3DWithNestVariogram.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.variogram import calculateOmnidirectionalVariogram3D 2 | from tfinterpy.gslib.fileUtils import readGslibPoints 3 | import tfinterpy.vtk.colorMap as CM 4 | from tfinterpy.vtk.rendering import createGridActor, rendering 5 | from tfinterpy.vtk.fileUtils import saveVTKGrid 6 | # import vtk dependencies first 7 | from tfinterpy.tf.variogramLayer import getNestVariogramLayer 8 | from tfinterpy.tf.krige import TFSK 9 | from tfinterpy.grid import Grid3D 10 | from tfinterpy.utils import calcVecs 11 | import matplotlib.pyplot as plt 12 | import tensorflow as tf 13 | 14 | 15 | if __name__ == "__main__": 16 | print(tf.config.experimental.list_physical_devices('CPU')) # Prints all CPU devices. 17 | print(tf.config.experimental.list_physical_devices('GPU')) # Prints all GPU devices. 18 | 19 | filePath = "data/sample_data.gslib" 20 | N = 8 21 | df = readGslibPoints(filePath)# Read 3d points from gslib file. 22 | print(df.describe()) 23 | samples = df[['x', 'y', 'z', 'porosity']].values 24 | 25 | # Create linear 3D grid. 26 | grid = Grid3D() 27 | grid.rectlinear((100, 100, 10), (samples[:, 0].min(), samples[:, 0].max()), 28 | (samples[:, 1].min(), samples[:, 1].max()), (samples[:, 2].min(), samples[:, 2].max())) 29 | 30 | # Calculate nested variation function. 31 | nestVariogram, variogramBuilders = calculateOmnidirectionalVariogram3D(samples, [5, 5]) 32 | for vb in variogramBuilders: 33 | plt.figure() 34 | vb.showVariogram() 35 | plt.show() 36 | # Get nested variation function layer. 37 | vl = getNestVariogramLayer(variogramBuilders, nestVariogram.unitVectors) 38 | 39 | exe = TFSK(samples, '3d')# Create a sk(tensorflow version) interpolator. 40 | # Specify the GPU to be used. 41 | with tf.device("/GPU:0"): 42 | # Perform interpolation of all points in the grid. 43 | grid.pro, grid.sigma = exe.execute(grid.points(), N, vl, 10000) 44 | 45 | print(exe.crossValidateKFold(10, N, vl))# Perform k-fold validation and print result. 46 | print(exe.crossValidate(N, vl))# Perform leave-one-out validation and print result. 47 | 48 | # Create an actor representing a rectilinear grid and use the interpolation results for color mapping. 49 | actor = createGridActor(*grid.dim, grid.x, grid.y, grid.z, grid.pro, [samples[:, 3].min(), samples[:, 3].max()], 50 | CM.Rainbow) 51 | rendering(actor)# Rendering vtkActor. 52 | # Create an actor representing a rectilinear grid and use the kriging variances for color mapping. 53 | actor = createGridActor(*grid.dim, grid.x, grid.y, grid.z, grid.sigma, None, CM.Rainbow) 54 | rendering(actor)# Rendering vtkActor. 55 | saveVTKGrid('savedData/grid.vtk', actor.GetMapper().GetInput())# Save grid data(kriging variances) to vtk file. 56 | 57 | -------------------------------------------------------------------------------- /examples/variogram.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | from tfinterpy.variogram import VariogramBuilder 3 | from tfinterpy.variogramExp import search2d 4 | from ncFileUtil import getSamples 5 | from tfinterpy.utils import calcVecs, calcHAVByVecs 6 | import numpy as np 7 | 8 | if __name__ == "__main__": 9 | filePath = "data/tatitlek_815_mhhw_2011.nc" 10 | W, H = 200, 200 11 | M = 100 12 | offset = (100, 100) 13 | 14 | # Get sample points and original elevation data from netcdf file 15 | # containing Digital Elevation Model data. 16 | samples, lats, lons, ele = getSamples(filePath, 'lat', 'lon', 'Band1', offset, (W, H), M) 17 | vecs = calcVecs(samples, repeat=False)# Calculate the vectors between sampling points. 18 | hav = calcHAVByVecs(vecs)# Calculate distance, angle, semivariance by vectors. 19 | lagNum = 20 20 | lag = hav[:, 0].max() / 2 / lagNum 21 | lagTole = lag * 0.5 22 | angles = hav[:, 1] 23 | buckets = [] 24 | portionNum = 8 25 | portion = np.pi / portionNum 26 | for i in range(portionNum): 27 | count = np.where((angles > portion * i) & (angles < portion * (i + 1)))[0].shape[0] 28 | buckets.append(count) 29 | idx = np.argmax(buckets) 30 | angle = portion * idx 31 | angleTole = portion 32 | bandWidth = hav[:, 0].mean() / 10 33 | #Search for lags 34 | lags, _ = search2d(vecs[:, :2], hav[:, 2], lagNum, lag, lagTole, angle, angleTole, bandWidth) 35 | vb = VariogramBuilder(lags)# Create a VariogramBuilder object. 36 | plt.figure() 37 | vb.showVariogram()# Plot variogram function. 38 | plt.show() 39 | -------------------------------------------------------------------------------- /figs/OK3D.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czwchenzhun/tfinterpy/9dc3b97260ec8b1d9d6631c33c3e19c298bb6f4a/figs/OK3D.jpg -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | matplotlib==3.9.4 2 | numpy==2.0.2 3 | pandas==2.2.3 4 | PyQt5==5.15.11 5 | scipy==1.13.1 6 | tensorflow==2.18.0 7 | tensorflow-gpu==2.18.0 8 | vtk==9.4.1 -------------------------------------------------------------------------------- /src/tfinterpy/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czwchenzhun/tfinterpy/9dc3b97260ec8b1d9d6631c33c3e19c298bb6f4a/src/tfinterpy/__init__.py -------------------------------------------------------------------------------- /src/tfinterpy/grid.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | class Grid2D: 5 | ''' 6 | Classes used to represent a two-dimensional grid. 7 | ''' 8 | 9 | def __init__(self): 10 | self.x = None 11 | self.y = None 12 | self.xran = None 13 | self.yran = None 14 | self._xy = None 15 | self.dim = [-1, -1] #width and height 16 | 17 | def rectlinear(self, dim, xran, yran): 18 | ''' 19 | Initialize the two-dimensional grid according to the dimension, x range, y range. 20 | 21 | :param dim: array_like, array containing two integer. [width, height]. 22 | :param xran: array_like, [xbegin, xend]. So the step of x is equal to (xend-xbegin)/(width-1). 23 | :param yran: array_like, [ybegin, yend]. 24 | :return: None 25 | ''' 26 | self.dim = dim 27 | self.xran = xran 28 | self.yran = yran 29 | xstep = (xran[1] - xran[0]) / (dim[0] - 1) 30 | self.x = np.array([(i * xstep + xran[0]) for i in range(dim[0])]) 31 | ystep = (yran[1] - yran[0]) / (dim[1] - 1) 32 | self.y = np.array([(i * ystep + yran[0]) for i in range(dim[1])]) 33 | self._xy = None 34 | 35 | def setXCoords(self, xcoords): 36 | ''' 37 | Sets the x coordinate of the grid. 38 | 39 | :param xcoords: array_like, array containing all the coordinates along the x axis. 40 | :return: None 41 | ''' 42 | self.x = np.array(xcoords) 43 | self.dim[0] = len(self.x) 44 | self.xran = [self.x.min(), self.x.max()] 45 | self._xy = None 46 | 47 | def setYCoords(self, ycoords): 48 | ''' 49 | Sets the y coordinate of the grid. 50 | 51 | :param ycoords: array_like, array containing all the coordinates along the y axis. 52 | :return: None 53 | ''' 54 | self.y = np.array(ycoords) 55 | self.dim[1] = len(self.y) 56 | self.yran = [self.y.min(), self.y.max()] 57 | self._xy = None 58 | 59 | def points(self): 60 | ''' 61 | Returns an ndarray containing all coordinates on the grid, 62 | and the shape of the array is (width*height, 2). 63 | 64 | :return: ndarray 65 | ''' 66 | if self._xy is None: 67 | self._xy = np.zeros((self.dim[1], self.dim[0], 2)) 68 | for i in range(self.dim[1]): 69 | self._xy[i, :, 0] = self.x 70 | for i in range(self.dim[0]): 71 | self._xy[:, i, 1] = self.y 72 | self._xy.resize((self.dim[0] * self.dim[1], 2)) 73 | return self._xy 74 | 75 | 76 | class Grid3D: 77 | ''' 78 | Classes used to represent a three-dimensional grid. 79 | ''' 80 | 81 | def __init__(self): 82 | self.x = None 83 | self.y = None 84 | self.z = None 85 | self.xran = None 86 | self.yran = None 87 | self.zran = None 88 | self._xyz = None 89 | self.dim = [-1, -1, -1] # width(x), height(y), long(z) 90 | 91 | def rectlinear(self, dim, xran, yran, zran): 92 | ''' 93 | Initialize the three-dimensional grid according to the dimension, x range, y range, xrange. 94 | 95 | :param dim: array_like, array containing two integer. [width, height]. 96 | :param xran: array_like, [xbegin, xend]. So the step of x is equal to (xend-xbegin)/(width-1). 97 | :param yran: array_like, [ybegin, yend]. 98 | :param zran: array_like, [zbegin, zend]. 99 | :return: None 100 | ''' 101 | self.dim = dim 102 | self.xran = xran 103 | self.yran = yran 104 | self.zran = zran 105 | xstep = (xran[1] - xran[0]) / (dim[0] - 1) 106 | self.x = np.array([(i * xstep + xran[0]) for i in range(dim[0])]) 107 | ystep = (yran[1] - yran[0]) / (dim[1] - 1) 108 | self.y = np.array([(i * ystep + yran[0]) for i in range(dim[1])]) 109 | zstep = (zran[1] - zran[0]) / (dim[2] - 1) 110 | self.z = np.array([(i * zstep + zran[0]) for i in range(dim[2])]) 111 | self._xyz = None 112 | 113 | def setXCoords(self, xcoords): 114 | ''' 115 | Sets the x coordinate of the grid. 116 | 117 | :param xcoords: array_like, array containing all the coordinates along the x axis. 118 | :return: None 119 | ''' 120 | self.x = np.array(xcoords) 121 | self.dim[0] = len(self.x) 122 | self.xran = [self.x.min(), self.x.max()] 123 | self._xyz = None 124 | 125 | def setYCoords(self, ycoords): 126 | ''' 127 | Sets the y coordinate of the grid. 128 | 129 | :param ycoords: array_like, array containing all the coordinates along the y axis. 130 | :return: None 131 | ''' 132 | self.y = np.array(ycoords) 133 | self.dim[1] = len(self.y) 134 | self.yran = [self.y.min(), self.y.max()] 135 | self._xyz = None 136 | 137 | def setZCoords(self, zcoords): 138 | ''' 139 | Sets the z coordinate of the grid. 140 | 141 | :param zcoords: array_like, array containing all the coordinates along the z axis. 142 | :return: None 143 | ''' 144 | self.z = np.array(zcoords) 145 | self.dim[2] = len(self.z) 146 | self.zran = [self.z.min(), self.z.max()] 147 | self._xyz = None 148 | 149 | def points(self): 150 | ''' 151 | Returns an ndarray containing all coordinates on the grid, 152 | and the shape of the array is (width*height*long, 3). 153 | 154 | :return: ndarray 155 | ''' 156 | if self._xyz is None: 157 | self._xyz = np.zeros((self.dim[2], self.dim[1], self.dim[0], 3)) 158 | for i in range(self.dim[2]): 159 | for j in range(self.dim[1]): 160 | self._xyz[i, j, :, 0] = self.x 161 | for j in range(self.dim[0]): 162 | self._xyz[i, :, j, 1] = self.y 163 | self._xyz[i, :, :, 2] = self.z[i] 164 | self._xyz.resize((self.dim[0] * self.dim[1] * self.dim[2], 3)) 165 | return self._xyz 166 | -------------------------------------------------------------------------------- /src/tfinterpy/gslib/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2022/3/28 12:02 3 | # @Author : UCCU 4 | -------------------------------------------------------------------------------- /src/tfinterpy/gslib/fileUtils.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | 4 | def readGslibPoints(filePath): 5 | ''' 6 | Read points data from gslib file. 7 | 8 | :param filePath: str. 9 | :return: DataFrame object. 10 | ''' 11 | columnNames = [] 12 | with open(filePath, 'r') as fi: 13 | fi.readline() 14 | n = int(fi.readline().strip()) 15 | for i in range(n): 16 | columnNames.append(fi.readline().strip()) 17 | fi.close() 18 | df = pd.read_csv(filePath, sep=',|\s+', skiprows=n + 2, header=None, engine="python") 19 | df.columns = columnNames 20 | return df 21 | 22 | 23 | def saveGslibPoints(filePath, colNames, ndarray, comment="#"): 24 | ''' 25 | Save points data to gslib file. 26 | 27 | :param filePath: str. 28 | :param colNames: list, column names. 29 | :param ndarray: ndarray, points and properties data. 30 | :param comment: str, comment on the first line of the gslib file. 31 | :return: None. 32 | ''' 33 | fo = open(filePath, 'w') 34 | fo.write(comment + '\n') 35 | fo.write('{}\n'.format(len(colNames))) 36 | for name in colNames: 37 | fo.write(name + '\n') 38 | df = pd.DataFrame(ndarray) 39 | df.to_csv(fo, sep=' ', line_terminator='\n', index=False, header=False) 40 | fo.close() 41 | 42 | 43 | def saveGslibGrid(filePath, dim, begin, step, colNames, ndarray, comment=None): 44 | ''' 45 | Save rectilinear grid data to gslib file. 46 | 47 | :param filePath: str. 48 | :param dim: list, [xnum, ynum, znum], xnum indicates the number of x coordinates. 49 | :param begin: list, [x,y,z], begin coordinates. 50 | :param step: list, [xstep,ystep,zstep], xstep indicates the step on x axis. 51 | :param colNames: list, column names. 52 | :param ndarray: ndarray, points and properties data. 53 | :param comment: str, comment on the first line of the gslib file. 54 | :return: None. 55 | ''' 56 | fo = open(filePath, 'w') 57 | if comment is not None: 58 | fo.write('#' + comment + '\n') 59 | line = ' '.join(list(map(lambda x: str(x), dim))) 60 | fo.write(line + '\n') 61 | line = ' '.join(list(map(lambda x: str(x), begin))) 62 | fo.write(line + '\n') 63 | line = ' '.join(list(map(lambda x: str(x), step))) 64 | fo.write(line + '\n') 65 | df = pd.DataFrame(ndarray) 66 | df.columns = colNames 67 | df.to_csv(fo, sep=' ', line_terminator='\n', index=False) 68 | fo.close() 69 | -------------------------------------------------------------------------------- /src/tfinterpy/gui/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2022/3/25 12:24 3 | # @Author : UCCU 4 | -------------------------------------------------------------------------------- /src/tfinterpy/gui/canvas.py: -------------------------------------------------------------------------------- 1 | import matplotlib 2 | matplotlib.use("Qt5Agg") 3 | from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas 4 | from matplotlib.figure import Figure 5 | import matplotlib.pyplot as plt 6 | 7 | #Set the global font size of matplotlib. 8 | plt.rcParams.update({"font.size":16}) 9 | 10 | class Canvas(FigureCanvas): 11 | ''' 12 | Matploblib canvas for embedding Qt widget. 13 | ''' 14 | 15 | def __init__(self, width=5, height=4, dpi=100, parent=None): 16 | self.fig = Figure(figsize=(width, height), dpi=dpi) 17 | super(Canvas, self).__init__(self.fig) 18 | self.setParent(parent) -------------------------------------------------------------------------------- /src/tfinterpy/idw.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.utils import kSplit 2 | import numpy as np 3 | from scipy.spatial import cKDTree 4 | 5 | 6 | class IDW: 7 | ''' 8 | Inverse Distance Weighted interpolator. 9 | ''' 10 | 11 | def __init__(self, samples, mode='2d'): 12 | ''' 13 | Initialize the interpolator using sample points. 14 | 15 | :param samples: ndarray, array containing all sample points. The last column must be the properties. 16 | For the case of two-dimensional interpolation, where each item is represented by [x,y,property]. 17 | For the case of three-dimensional interpolation, where each item is represented by [x,y,z,property]. 18 | :param mode: str, '2d' or '3d'. 19 | ''' 20 | self.samples = samples 21 | self.mode = mode 22 | self._i = 2 23 | if mode == '3d' or mode == '3D': 24 | self._i = 3 25 | 26 | def execute(self, points, N=8, alpha=2): 27 | ''' 28 | Perform interpolation for points and return result values. 29 | 30 | :param points: ndarray, array containing all the coordinate points to be interpolated. 31 | :param N: integer, neighborhood size. 32 | :param alpha: number, distance power factor. 33 | :return: ndarray, one-dimensional array containing interpolation result. 34 | ''' 35 | tree = cKDTree(self.samples[:, :self._i]) 36 | nbd, nbIdx = tree.query(points, k=N, eps=0.0) 37 | properties = np.zeros((len(points))) 38 | for idx, indice in enumerate(nbIdx): 39 | hs = nbd[idx] 40 | hs = hs ** alpha 41 | inv = 1 / (hs + 1e-8) 42 | total = np.sum(inv) 43 | weights = inv / total 44 | pro = np.dot(self.samples[:, self._i][indice], weights) 45 | properties[idx] = pro 46 | return properties 47 | 48 | def crossValidateKFold(self, K=10, N=8, alpha=2): 49 | ''' 50 | Perform k-fold cross validation on sample points. 51 | 52 | :param K: integer. 53 | :param N: integer, neighborhood size. 54 | :param alpha: number, distance power factor. 55 | :return: tuple, tuple containing three list. 56 | The first list contains the absolute mean error for each fold, 57 | the second list contains the absolute standard deviation error for each fold, 58 | the last list contains the origin error for each fold. 59 | ''' 60 | splits = kSplit(self.samples, K) 61 | absErrorMeans = [] 62 | absErrorStds = [] 63 | originalErrorList = [] 64 | for i in range(K): 65 | concatenateList = [] 66 | for j in range(K): 67 | if j == i: 68 | continue 69 | concatenateList.append(splits[j]) 70 | p1 = np.concatenate(concatenateList) 71 | p2 = splits[i] 72 | if len(p2) == 0: 73 | break 74 | exe = IDW(p1, self.mode) 75 | es = exe.execute(p2[:, :self._i], N, alpha) 76 | error = p2[:, self._i] - es 77 | absError = np.abs(error) 78 | mean = absError.mean() 79 | std = absError.std() 80 | originalErrorList.append(error) 81 | absErrorMeans.append(mean) 82 | absErrorStds.append(std) 83 | return absErrorMeans, absErrorStds, originalErrorList 84 | 85 | def crossValidate(self, N=8, alpha=2): 86 | ''' 87 | Perform leave-one-out cross validation on sample points. 88 | 89 | :param N: integer, neighborhood size. 90 | :param alpha: number, distance power factor. 91 | :return: tuple, tuple containing absolute mean error, absolute standard deviation error and origin error(ndarray). 92 | ''' 93 | tree = cKDTree(self.samples[:, :self._i]) 94 | nbd, nb_idx = tree.query(self.samples[:, :self._i], k=N + 1, eps=0.0) 95 | properties = np.zeros((len(self.samples))) 96 | for idx, indice in enumerate(nb_idx): 97 | indice = indice[1:] 98 | hs = nbd[idx][1:] 99 | hs = hs ** alpha 100 | inv = 1 / (hs + 1e-8) 101 | total = np.sum(inv) 102 | weights = inv / total 103 | pro = np.dot(self.samples[:, self._i][indice], weights) 104 | properties[idx] = pro 105 | error = properties - self.samples[:, self._i] 106 | absError = np.abs(error) 107 | mean = absError.mean() 108 | std = absError.std() 109 | return mean, std, error 110 | -------------------------------------------------------------------------------- /src/tfinterpy/krige.py: -------------------------------------------------------------------------------- 1 | from scipy.spatial import cKDTree 2 | import numpy as np 3 | from tfinterpy.utils import kSplit, calcVecs 4 | from tfinterpy.variogram import NestVariogram 5 | 6 | 7 | class SK: 8 | ''' 9 | Simple Kriging interpolator. 10 | ''' 11 | 12 | def __init__(self, samples, mode="2d"): 13 | ''' 14 | Initialize the interpolator using sample points. 15 | 16 | :param samples: ndarray, array containing all sample points. The last column must be the properties. 17 | For the case of two-dimensional interpolation, where each item is represented by [x,y,property]. 18 | For the case of three-dimensional interpolation, where each item is represented by [x,y,z,property]. 19 | :param mode: str, '2d' or '3d'. 20 | ''' 21 | self.samples = samples 22 | self.mode = mode 23 | self._i = 2 24 | if mode.lower() == '3d': 25 | self._i = 3 26 | self.innerVecs = None 27 | 28 | def execute(self, points, N=8, variogram=None): 29 | ''' 30 | Perform interpolation for points and return result values. 31 | 32 | :param points: ndarray, array containing all the coordinate points to be interpolated. 33 | :param N: integer, neighborhood size. 34 | :param variogram: variogram function or nest variogram object, default None. 35 | A linear variogram (lambda x:x) is used when the variogram is None. 36 | :return: tuple, tuple containing tow ndarray. 37 | The first ndarray representing the interpolation result, 38 | the second ndarray representing the kriging variance. 39 | ''' 40 | if self.innerVecs is None: 41 | self.__calcInnerVecs__() 42 | if variogram is None: 43 | self.innerVars = np.linalg.norm(self.innerVecs, axis=2) 44 | variogram = lambda x: x 45 | elif variogram.__class__ == NestVariogram: 46 | self.innerVars = variogram(self.innerVecs) 47 | else: 48 | self.innerVars = np.linalg.norm(self.innerVecs, axis=2) 49 | self.innerVars = variogram(self.innerVars) 50 | if self.innerVars.shape[-1] == 1: 51 | self.innerVars = self.innerVars.reshape(self.innerVars.shape[:-1]) 52 | 53 | tree = cKDTree(self.samples[:, :self._i]) 54 | nbd, nbIdx = tree.query(points, k=N, eps=0.0) 55 | properties = np.zeros((len(points))) 56 | sigmas = np.zeros((len(points))) 57 | for idx, indice in enumerate(nbIdx): 58 | kmat = self.innerVars[indice][:, indice] 59 | if variogram.__class__ == NestVariogram: 60 | mvec = self.samples[indice, :self._i] - points[idx] 61 | mvec = variogram(mvec) 62 | else: 63 | mvec = variogram(nbd[idx]) 64 | np.fill_diagonal(kmat, 0.0) 65 | try: 66 | lambvec = np.linalg.inv(kmat).dot(mvec) 67 | except: 68 | lambvec = np.linalg.pinv(kmat).dot(mvec) 69 | pro = np.dot(self.samples[:, self._i][indice], lambvec) 70 | properties[idx] = pro + np.mean(self.samples[:, self._i][indice]) * (1 - np.sum(lambvec)) 71 | sigmas[idx] = np.dot(lambvec, mvec) 72 | return properties, sigmas 73 | 74 | def crossValidateKFold(self, K=10, N=8, variogram=None): 75 | ''' 76 | Perform k-fold cross validation on sample points. 77 | 78 | :param K: integer. 79 | :param N: integer, neighborhood size. 80 | :param variogram: variogram function or nest variogram object, default None. 81 | A linear variogram (lambda x:x) is used when the variogram is None. 82 | :return: tuple, tuple containing three list. 83 | The first list contains the absolute mean error for each fold, 84 | the second list contains the absolute standard deviation error for each fold, 85 | the last list contains the origin error for each fold. 86 | ''' 87 | splits = kSplit(self.samples, K) 88 | absErrorMeans = [] 89 | absErrorStds = [] 90 | originalErrorList = [] 91 | for i in range(K): 92 | concatenateList = [] 93 | for j in range(K): 94 | if j == i: 95 | continue 96 | concatenateList.append(splits[j]) 97 | p1 = np.concatenate(concatenateList) 98 | p2 = splits[i] 99 | if len(p2) == 0: 100 | break 101 | exe = SK(p1, self.mode) 102 | es, _ = exe.execute(p2[:, :self._i], N, variogram) 103 | error = p2[:, self._i] - es 104 | absError = np.abs(error) 105 | mean = absError.mean() 106 | std = absError.std() 107 | originalErrorList.append(error) 108 | absErrorMeans.append(mean) 109 | absErrorStds.append(std) 110 | return absErrorMeans, absErrorStds, originalErrorList 111 | 112 | def crossValidate(self, N=8, variogram=None): 113 | ''' 114 | Perform leave-one-out cross validation on sample points. 115 | 116 | :param N: integer, neighborhood size. 117 | :param variogram: variogram function or nest variogram object, default None. 118 | A linear variogram (lambda x:x) is used when the variogram is None. 119 | :return: tuple, tuple containing absolute mean error, absolute standard deviation error and origin error(ndarray). 120 | ''' 121 | if self.innerVecs is None: 122 | self.__calcInnerVecs__() 123 | if variogram is None: 124 | self.innerVars = np.linalg.norm(self.innerVecs, axis=2) 125 | variogram = lambda x: x 126 | elif variogram.__class__ == NestVariogram: 127 | self.innerVars = variogram(self.innerVecs) 128 | else: 129 | self.innerVars = np.linalg.norm(self.innerVecs, axis=2) 130 | self.innerVars = variogram(self.innerVars) 131 | if self.innerVars.shape[-1] == 1: 132 | self.innerVars = self.innerVars.reshape(self.innerVars.shape[:-1]) 133 | 134 | tree = cKDTree(self.samples[:, :self._i]) 135 | nbd, nbIdx = tree.query(self.samples[:, :self._i], k=N + 1, eps=0.0) 136 | properties = np.zeros((len(self.samples))) 137 | for idx, indice in enumerate(nbIdx): 138 | indice = indice[1:] 139 | kmat = self.innerVars[indice][:, indice] 140 | if variogram.__class__ == NestVariogram: 141 | mvec = self.samples[indice, :self._i] - self.samples[idx, :self._i] 142 | mvec = variogram(mvec) 143 | else: 144 | mvec = variogram(nbd[idx][1:]) 145 | np.fill_diagonal(kmat, 0.0) 146 | try: 147 | lambvec = np.linalg.inv(kmat).dot(mvec) 148 | except: 149 | lambvec = np.linalg.pinv(kmat).dot(mvec) 150 | pro = np.dot(self.samples[:, self._i][indice], lambvec) 151 | properties[idx] = pro + np.mean(self.samples[:, self._i][indice]) * (1 - np.sum(lambvec)) 152 | error = properties - self.samples[:, self._i] 153 | absError = np.abs(error) 154 | mean = absError.mean() 155 | std = absError.std() 156 | return mean, std, error 157 | 158 | def __calcInnerVecs__(self): 159 | ''' 160 | Compute vectors between sample points. 161 | 162 | :return: None. 163 | ''' 164 | innerVecs = calcVecs(self.samples[:, :self._i], includeSelf=True) 165 | self.innerVecs = innerVecs.reshape((self.samples.shape[0], self.samples.shape[0], self._i)) 166 | 167 | 168 | class OK: 169 | ''' 170 | Ordinary Kriging interpolator. 171 | ''' 172 | 173 | def __init__(self, samples, mode="2d"): 174 | ''' 175 | Initialize the interpolator using sample points. 176 | 177 | :param samples: ndarray, array containing all sample points. The last column must be the properties. 178 | For the case of two-dimensional interpolation, where each item is represented by [x,y,property]. 179 | For the case of three-dimensional interpolation, where each item is represented by [x,y,z,property]. 180 | :param mode: str, '2d' or '3d'. 181 | ''' 182 | self.samples = samples 183 | self.mode = mode 184 | self._i = 2 185 | if mode.lower() == '3d': 186 | self._i = 3 187 | self.innerVecs = None 188 | 189 | def execute(self, points, N=8, variogram=None): 190 | ''' 191 | Perform interpolation for points and return result values. 192 | 193 | :param points: ndarray, array containing all the coordinate points to be interpolated. 194 | :param N: integer, neighborhood size. 195 | :param variogram: variogram function or nest variogram object, default None. 196 | A linear variogram (lambda x:x) is used when the variogram is None. 197 | :return: tuple, tuple containing tow ndarray. 198 | The first ndarray representing the interpolation result, 199 | the second ndarray representing the kriging variance. 200 | ''' 201 | if self.innerVecs is None: 202 | self.__calcInnerVecs__() 203 | if variogram is None: 204 | self.innerVars = np.linalg.norm(self.innerVecs, axis=2) 205 | variogram = lambda x: x 206 | elif variogram.__class__ == NestVariogram: 207 | self.innerVars = variogram(self.innerVecs) 208 | else: 209 | self.innerVars = np.linalg.norm(self.innerVecs, axis=2) 210 | self.innerVars = variogram(self.innerVars) 211 | if self.innerVars.shape[-1] == 1: 212 | self.innerVars = self.innerVars.reshape(self.innerVars.shape[:-1]) 213 | 214 | tree = cKDTree(self.samples[:, :self._i]) 215 | nbd, nbIdx = tree.query(points, k=N, eps=0.0) 216 | properties = np.zeros((len(points))) 217 | sigmas = np.zeros((len(points))) 218 | kmat = np.ones((N + 1, N + 1)) 219 | kmat[N, N] = 0.0 220 | mvec = np.ones((N + 1,)) 221 | for idx, indice in enumerate(nbIdx): 222 | kmat[:N, :N] = self.innerVars[indice][:, indice] 223 | if variogram.__class__ == NestVariogram: 224 | vecs = self.samples[indice, :self._i] - points[idx] 225 | mvec[:N] = variogram(vecs) 226 | else: 227 | mvec[:N] = variogram(nbd[idx]) 228 | np.fill_diagonal(kmat, 0.0) 229 | try: 230 | lambvec = np.linalg.inv(kmat).dot(mvec) 231 | except: 232 | lambvec = np.linalg.pinv(kmat).dot(mvec) 233 | properties[idx] = np.dot(self.samples[indice, self._i], lambvec[:N]) 234 | sigmas[idx] = np.dot(lambvec, mvec) 235 | return properties, sigmas 236 | 237 | def crossValidateKFold(self, K=10, N=8, variogram=None): 238 | ''' 239 | Perform k-fold cross validation on sample points. 240 | 241 | :param K: integer. 242 | :param N: integer, neighborhood size. 243 | :param variogram: variogram function or nest variogram object, default None. 244 | A linear variogram (lambda x:x) is used when the variogram is None. 245 | :return: tuple, tuple containing three list. 246 | The first list contains the absolute mean error for each fold, 247 | the second list contains the absolute standard deviation error for each fold, 248 | the last list contains the origin error for each fold. 249 | ''' 250 | splits = kSplit(self.samples, K) 251 | absErrorMeans = [] 252 | absErrorStds = [] 253 | originalErrorList = [] 254 | for i in range(K): 255 | concatenateList = [] 256 | for j in range(K): 257 | if j == i: 258 | continue 259 | concatenateList.append(splits[j]) 260 | p1 = np.concatenate(concatenateList) 261 | p2 = splits[i] 262 | if len(p2) == 0: 263 | break 264 | exe = OK(p1, self.mode) 265 | es, _ = exe.execute(p2[:, :self._i], N, variogram) 266 | error = p2[:, self._i] - es 267 | absError = np.abs(error) 268 | mean = absError.mean() 269 | std = absError.std() 270 | originalErrorList.append(error) 271 | absErrorMeans.append(mean) 272 | absErrorStds.append(std) 273 | return absErrorMeans, absErrorStds, originalErrorList 274 | 275 | def crossValidate(self, N=8, variogram=None): 276 | ''' 277 | Perform leave-one-out cross validation on sample points. 278 | 279 | :param N: integer, neighborhood size. 280 | :param variogram: variogram function or nest variogram object, default None. 281 | A linear variogram (lambda x:x) is used when the variogram is None. 282 | :return: tuple, tuple containing absolute mean error, absolute standard deviation error and origin error(ndarray). 283 | ''' 284 | if self.innerVecs is None: 285 | self.__calcInnerVecs__() 286 | if variogram is None: 287 | self.innerVars = np.linalg.norm(self.innerVecs, axis=2) 288 | variogram = lambda x: x 289 | elif variogram.__class__ == NestVariogram: 290 | self.innerVars = variogram(self.innerVecs) 291 | else: 292 | self.innerVars = np.linalg.norm(self.innerVecs, axis=2) 293 | self.innerVars = variogram(self.innerVars) 294 | if self.innerVars.shape[-1] == 1: 295 | self.innerVars = self.innerVars.reshape(self.innerVars.shape[:-1]) 296 | 297 | tree = cKDTree(self.samples[:, :self._i]) 298 | nbd, nbIdx = tree.query(self.samples[:, :self._i], k=N + 1, eps=0.0) 299 | properties = np.zeros((len(self.samples))) 300 | kmat = np.ones((N + 1, N + 1)) 301 | kmat[N, N] = 0.0 302 | mvec = np.ones((N + 1,)) 303 | for idx, indice in enumerate(nbIdx): 304 | indice = indice[1:] 305 | kmat[:N, :N] = self.innerVars[indice][:, indice] 306 | if variogram.__class__ == NestVariogram: 307 | vecs = self.samples[indice, :self._i] - self.samples[idx, :self._i] 308 | mvec[:N] = variogram(vecs) 309 | else: 310 | mvec[:N] = variogram(nbd[idx][1:]) 311 | np.fill_diagonal(kmat, 0.0) 312 | try: 313 | lambvec = np.linalg.inv(kmat).dot(mvec) 314 | except: 315 | lambvec = np.linalg.pinv(kmat).dot(mvec) 316 | properties[idx] = np.dot(self.samples[:, self._i][indice], lambvec[:N]) 317 | error = properties - self.samples[:, self._i] 318 | absError = np.abs(error) 319 | mean = absError.mean() 320 | std = absError.std() 321 | return mean, std, error 322 | 323 | def __calcInnerVecs__(self): 324 | ''' 325 | Compute vectors between sample points. 326 | 327 | :return: None. 328 | ''' 329 | innerVecs = calcVecs(self.samples[:, :self._i], includeSelf=True) 330 | self.innerVecs = innerVecs.reshape((self.samples.shape[0], self.samples.shape[0], self._i)) 331 | -------------------------------------------------------------------------------- /src/tfinterpy/tf/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czwchenzhun/tfinterpy/9dc3b97260ec8b1d9d6631c33c3e19c298bb6f4a/src/tfinterpy/tf/__init__.py -------------------------------------------------------------------------------- /src/tfinterpy/tf/commonLayer.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import tensorflow.keras.backend as K 3 | from tensorflow.keras import layers 4 | 5 | class InvLayer(layers.Layer): 6 | def __init__(self): 7 | super(InvLayer, self).__init__() 8 | 9 | def call(self, mat): 10 | return tf.linalg.pinv(mat) 11 | 12 | class MeanLayer(layers.Layer): 13 | def __init__(self): 14 | super(MeanLayer, self).__init__() 15 | 16 | def call(self, vec): 17 | return K.mean(vec, axis=1) 18 | 19 | class SumLayer(layers.Layer): 20 | def __init__(self): 21 | super(SumLayer, self).__init__() 22 | 23 | def call(self, vec): 24 | return K.sum(vec, axis=1) -------------------------------------------------------------------------------- /src/tfinterpy/tf/idw.py: -------------------------------------------------------------------------------- 1 | import tensorflow.keras.backend as K 2 | from tensorflow.keras import layers 3 | from tensorflow.keras.models import Model 4 | from scipy.spatial import cKDTree 5 | import numpy as np 6 | from tfinterpy.utils import kSplit 7 | from tfinterpy.tf.commonLayer import SumLayer 8 | 9 | def IDWModel(n=8, alpha=2): 10 | ''' 11 | Construction a keras model for Inverse Distance Weighted algorithm. 12 | 13 | :param n: integer, neighborhood size. 14 | :param alpha: number, distance power factor. 15 | :return: keras' Model object. 16 | ''' 17 | h_ = layers.Input(shape=(n,)) 18 | pro = layers.Input(shape=(n,)) 19 | h = h_ ** alpha 20 | hinv = 1 / (h + 1e-8) 21 | total = SumLayer()(hinv) 22 | total = layers.Reshape((1,))(total) 23 | weights = hinv / total 24 | estimate = layers.Dot(1)([pro, weights]) 25 | model = Model(inputs=[h_, pro], outputs=estimate) 26 | return model 27 | 28 | 29 | class TFIDW: 30 | ''' 31 | Tensorflow version of Inverse Distance Weighted interpolator. 32 | ''' 33 | 34 | def __init__(self, samples, mode='2d'): 35 | ''' 36 | Initialize the interpolator using sample points. 37 | 38 | :param samples: ndarray, array containing all sample points. The last column must be the properties. 39 | For the case of two-dimensional interpolation, where each item is represented by [x,y,property]. 40 | For the case of three-dimensional interpolation, where each item is represented by [x,y,z,property]. 41 | :param mode: str, '2d' or '3d'. 42 | ''' 43 | self.samples = samples 44 | self.mode = mode 45 | self._i = 2 46 | if mode == '3d' or mode == '3D': 47 | self._i = 3 48 | 49 | def execute(self, points, N=8, alpha=2, batch_size=1000): 50 | ''' 51 | Perform interpolation for points and return result values. 52 | 53 | :param points: ndarray, array containing all the coordinate points to be interpolated. 54 | :param N: integer, neighborhood size. 55 | :param alpha: number, distance power factor. 56 | :param batch_size: integer, size of each batch of data to be calculated. 57 | :return: ndarray, one-dimensional array containing interpolation result. 58 | ''' 59 | self.model = IDWModel(N, alpha) 60 | tree = cKDTree(self.samples[:, :self._i]) 61 | step = batch_size * 2 62 | num = int(np.ceil(len(points) / step)) 63 | pros = np.empty((0, 1)) 64 | for i in range(num): 65 | begin = i * step 66 | end = (i + 1) * step 67 | points_ = points[begin:end] 68 | nbd, nbIdx = tree.query(points_, k=N, eps=0.0) 69 | hList = [] 70 | neighProList = [] 71 | for idx, indice in enumerate(nbIdx): 72 | hList.append(nbd[idx]) 73 | neighProList.append(self.samples[indice, self._i]) 74 | hArr = np.array(hList) 75 | neighProArr = np.array(neighProList) 76 | pro = self.model.predict([hArr, neighProArr], batch_size=batch_size) 77 | pros = np.append(pros, pro) 78 | return pros 79 | 80 | def crossValidateKFold(self, K=10, N=8, alpha=2): 81 | ''' 82 | Perform k-fold cross validation on sample points. 83 | 84 | :param K: integer. 85 | :param N: integer, neighborhood size. 86 | :param alpha: number, distance power factor. 87 | :return: tuple, tuple containing three list. 88 | The first list contains the absolute mean error for each fold, 89 | the second list contains the absolute standard deviation error for each fold, 90 | the last list contains the origin error for each fold. 91 | ''' 92 | splits = kSplit(self.samples, K) 93 | absErrorMeans = [] 94 | absErrorStds = [] 95 | originalErrorList = [] 96 | for i in range(K): 97 | concatenateList = [] 98 | for j in range(K): 99 | if j == i: 100 | continue 101 | concatenateList.append(splits[j]) 102 | p1 = np.concatenate(concatenateList) 103 | p2 = splits[i] 104 | if len(p2) == 0: 105 | break 106 | exe = TFIDW(p1, self.mode) 107 | es = exe.execute(p2[:, :self._i], N, alpha) 108 | error = p2[:, self._i] - es 109 | absError = np.abs(error) 110 | mean = absError.mean() 111 | std = absError.std() 112 | originalErrorList.extend(error.reshape(-1).tolist()) 113 | absErrorMeans.append(mean) 114 | absErrorStds.append(std) 115 | return absErrorMeans, absErrorStds, originalErrorList 116 | 117 | def crossValidate(self, N=8, alpha=2): 118 | ''' 119 | Perform leave-one-out cross validation on sample points. 120 | 121 | :param N: integer, neighborhood size. 122 | :param alpha: number, distance power factor. 123 | :return: tuple, tuple containing absolute mean error, absolute standard deviation error and origin error(ndarray). 124 | ''' 125 | self.model = IDWModel(N, alpha) 126 | tree = cKDTree(self.samples[:, :self._i]) 127 | nbd, nb_idx = tree.query(self.samples[:, :self._i], k=N + 1, eps=0.0) 128 | hList = [] 129 | neighProList = [] 130 | for idx, indice in enumerate(nb_idx): 131 | hList.append(nbd[idx][1:]) 132 | neighProList.append(self.samples[indice[1:], self._i]) 133 | hArr = np.array(hList) 134 | neighProArr = np.array(neighProList) 135 | pros = self.model.predict([hArr, neighProArr], batch_size=1000) 136 | pros = pros.reshape(-1) 137 | error = pros - self.samples[:, self._i] 138 | absError = np.abs(error) 139 | mean = absError.mean() 140 | std = absError.std() 141 | return mean, std, error 142 | -------------------------------------------------------------------------------- /src/tfinterpy/tf/krige.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import tensorflow.keras.backend as K 3 | from tensorflow.keras import layers 4 | from tensorflow.keras.models import Model 5 | from scipy.spatial import cKDTree 6 | import numpy as np 7 | from tfinterpy.utils import kSplit, calcVecs 8 | from tfinterpy.tf.variogramLayer import NestVariogramLayer 9 | from tfinterpy.tf.commonLayer import InvLayer, MeanLayer, SumLayer 10 | 11 | # tf.keras.backend.set_floatx('float64') 12 | 13 | def SKModel(n=8, variogramLayer=None, vecDim=2): 14 | ''' 15 | Construction a keras model for Simple Kriging algorithm. 16 | 17 | :param n: integer, neighborhood size. 18 | :param variogramLayer: keras' layer, layer representing a variogram function. 19 | :param vecDim: integer, the dimension of the vector to be calculated. 20 | :return: keras' Model object. 21 | ''' 22 | kmat = layers.Input(shape=(n, n)) 23 | if variogramLayer != None and variogramLayer.__class__ == NestVariogramLayer: 24 | mvec_ = layers.Input(shape=(n, vecDim)) 25 | else: 26 | mvec_ = layers.Input(shape=(n,)) 27 | pro = layers.Input(shape=(n,)) 28 | if variogramLayer != None: 29 | mvec = variogramLayer(mvec_) 30 | else: 31 | mvec = mvec_ 32 | mvec = layers.Reshape((n, 1))(mvec) 33 | kmatInv = InvLayer()(kmat) 34 | lambvec = layers.Dot(1)([kmatInv, mvec]) 35 | estimate = layers.Dot(1)([pro, lambvec]) 36 | promean = MeanLayer()(pro) 37 | eps = SumLayer()(lambvec) 38 | promean = layers.Reshape((1,))(promean) 39 | eps = layers.Reshape((1,))(eps) 40 | estimate = estimate + promean * (1 - eps) 41 | lambvec = layers.Reshape((n,))(lambvec) 42 | mvec = layers.Reshape((n,))(mvec) 43 | sigma = layers.Dot(1)([lambvec, mvec]) 44 | model = Model(inputs=[kmat, mvec_, pro], outputs=[estimate, sigma]) 45 | return model 46 | 47 | 48 | class TFSK: 49 | ''' 50 | Tensorflow version of Simple Kriging interpolator. 51 | ''' 52 | 53 | def __init__(self, samples, mode='2d'): 54 | ''' 55 | Initialize the interpolator using sample points. 56 | 57 | :param samples: ndarray, array containing all sample points. The last column must be the properties. 58 | For the case of two-dimensional interpolation, where each item is represented by [x,y,property]. 59 | For the case of three-dimensional interpolation, where each item is represented by [x,y,z,property]. 60 | :param mode: str, '2d' or '3d'. 61 | ''' 62 | self.samples = samples 63 | self.mode = mode 64 | self._i = 2 65 | if mode.lower() == '3d': 66 | self._i = 3 67 | self.innerVecs = None 68 | 69 | def execute(self, points, N=8, variogramLayer=None, batch_size=10000): 70 | ''' 71 | Perform interpolation for points and return result values. 72 | 73 | :param points: ndarray, array containing all the coordinate points to be interpolated. 74 | :param N: integer, neighborhood size. 75 | :param variogramLayer: keras' layer, layer representing a variogram function. 76 | :param batch_size: integer, size of each batch of data to be calculated. 77 | :return: tuple, tuple containing tow ndarray. 78 | The first ndarray representing the interpolation result, 79 | the second ndarray representing the kriging variance. 80 | ''' 81 | self.N = N 82 | self.model = SKModel(N, variogramLayer, self._i) 83 | isNest = variogramLayer.__class__ == NestVariogramLayer 84 | if self.innerVecs is None: 85 | self.__calcInnerVecs__() 86 | if variogramLayer is None: 87 | self.innerVars = np.linalg.norm(self.innerVecs, axis=2) 88 | elif isNest: 89 | self.innerVars = variogramLayer(self.innerVecs).numpy() 90 | else: 91 | self.innerVars = np.linalg.norm(self.innerVecs, axis=2) 92 | self.innerVars = variogramLayer(self.innerVars).numpy() 93 | if self.innerVars.shape[-1] == 1: 94 | self.innerVars = self.innerVars.reshape(self.innerVars.shape[:-1]) 95 | 96 | tree = cKDTree(self.samples[:, :self._i]) 97 | step = batch_size * 3 98 | num = int(np.ceil(len(points) / step)) 99 | pros = np.empty((0, 1)) 100 | sigmas = np.empty((0, 1)) 101 | init = False 102 | for i in range(num): 103 | begin = i * step 104 | end = (i + 1) * step 105 | if end > len(points): 106 | end = len(points) 107 | if not init or i == num - 1: 108 | kmatArr = np.zeros((end - begin, N, N)) 109 | if isNest: 110 | mvecArr = np.zeros((end - begin, N, self._i)) 111 | else: 112 | mvecArr = np.zeros((end - begin, N)) 113 | neighProArr = np.zeros((end - begin, N)) 114 | init = True 115 | points_ = points[begin:end] 116 | nbd, nbIdx = tree.query(points_, k=N, eps=0.0) 117 | for idx, indice in enumerate(nbIdx): 118 | kmatArr[idx] = self.innerVars[indice][:, indice] 119 | if isNest: 120 | mvecArr[idx] = self.samples[indice, :self._i] - points_[idx] 121 | else: 122 | mvecArr[idx] = nbd[idx] 123 | neighProArr[idx] = self.samples[indice, self._i] 124 | pro, sigma = self.model.predict([kmatArr, mvecArr, neighProArr], batch_size=batch_size) 125 | pros = np.append(pros, pro) 126 | sigmas = np.append(sigmas, sigma) 127 | return pros, sigmas 128 | 129 | def crossValidateKFold(self, K=10, N=8, variogramLayer=None): 130 | ''' 131 | Perform k-fold cross validation on sample points. 132 | 133 | :param K: integer. 134 | :param N: integer, neighborhood size. 135 | :param variogramLayer: keras' layer, layer representing a variogram function. 136 | :return: tuple, tuple containing three list. 137 | The first list contains the absolute mean error for each fold, 138 | the second list contains the absolute standard deviation error for each fold, 139 | the last list contains the origin error for each fold. 140 | ''' 141 | splits = kSplit(self.samples, K) 142 | absErrorMeans = [] 143 | absErrorStds = [] 144 | originalErrorList = [] 145 | for i in range(K): 146 | concatenateList = [] 147 | for j in range(K): 148 | if j == i: 149 | continue 150 | concatenateList.append(splits[j]) 151 | p1 = np.concatenate(concatenateList) 152 | p2 = splits[i] 153 | if len(p2) == 0: 154 | break 155 | exe = TFSK(p1, self.mode) 156 | es, _ = exe.execute(p2[:, :self._i], N, variogramLayer) 157 | error = p2[:, self._i] - es 158 | absError = np.abs(error) 159 | mean = absError.mean() 160 | std = absError.std() 161 | originalErrorList.extend(error.reshape(-1).tolist()) 162 | absErrorMeans.append(mean) 163 | absErrorStds.append(std) 164 | return absErrorMeans, absErrorStds, originalErrorList 165 | 166 | def crossValidate(self, N=8, variogramLayer=None): 167 | ''' 168 | Perform leave-one-out cross validation on sample points. 169 | 170 | :param N: integer, neighborhood size. 171 | :param variogramLayer: keras' layer, layer representing a variogram function. 172 | :return: tuple, tuple containing absolute mean error, absolute standard deviation error and origin error(ndarray). 173 | ''' 174 | self.N = N 175 | self.model = SKModel(N, variogramLayer, self._i) 176 | isNest = variogramLayer.__class__ == NestVariogramLayer 177 | if self.innerVecs is None: 178 | self.__calcInnerVecs__() 179 | if variogramLayer is None: 180 | self.innerVars = np.linalg.norm(self.innerVecs, axis=2) 181 | elif isNest: 182 | self.innerVars = variogramLayer(self.innerVecs).numpy() 183 | else: 184 | self.innerVars = np.linalg.norm(self.innerVecs, axis=2) 185 | self.innerVars = variogramLayer(self.innerVars).numpy() 186 | if self.innerVars.shape[-1] == 1: 187 | self.innerVars = self.innerVars.reshape(self.innerVars.shape[:-1]) 188 | 189 | tree = cKDTree(self.samples[:, :self._i]) 190 | nbd, nbIdx = tree.query(self.samples[:, :self._i], k=N + 1, eps=0.0) 191 | L = len(self.samples) 192 | kmatArr = np.zeros((L, N, N)) 193 | if isNest: 194 | mvecArr = np.zeros((L, N, self._i)) 195 | else: 196 | mvecArr = np.zeros((L, N)) 197 | neighProArr = np.zeros((L, N)) 198 | for idx, indice in enumerate(nbIdx): 199 | indice = indice[1:] 200 | kmatArr[idx] = self.innerVars[indice][:, indice] 201 | if isNest: 202 | mvecArr[idx] = self.samples[indice, :self._i] - self.samples[idx, :self._i] 203 | else: 204 | mvecArr[idx] = nbd[idx][1:] 205 | neighProArr[idx] = self.samples[indice, self._i] 206 | pros, _ = self.model.predict([kmatArr, mvecArr, neighProArr], batch_size=10000) 207 | pros = pros.reshape(-1) 208 | error = pros - self.samples[:, self._i] 209 | absError = np.abs(error) 210 | mean = absError.mean() 211 | std = absError.std() 212 | return mean, std, error 213 | 214 | def __calcInnerVecs__(self): 215 | ''' 216 | Compute vectors between sample points. 217 | 218 | :return: None. 219 | ''' 220 | innerVecs = calcVecs(self.samples[:, :self._i], includeSelf=True) 221 | self.innerVecs = innerVecs.reshape((self.samples.shape[0], self.samples.shape[0], self._i)) 222 | 223 | 224 | def OKModel(n=8, variogramLayer=None, vecDim=2): 225 | ''' 226 | Construction a keras model for Ordinary Kriging algorithm. 227 | 228 | :param n: integer, neighborhood size. 229 | :param variogramLayer: keras' layer, layer representing a variogram function. 230 | :param vecDim: integer, the dimension of the vector to be calculated. 231 | :return: keras' Model object. 232 | ''' 233 | mat1 = np.ones((n + 1, n + 1)) 234 | mat1[n] = 0 235 | mat1[:, n] = 0 236 | mat1 = tf.constant(mat1) 237 | mat2 = np.zeros((n + 1, n + 1)) 238 | mat2[n] = 1 239 | mat2[:, n] = 1 240 | mat2[n, n] = 0 241 | mat2 = tf.constant(mat2) 242 | 243 | mat3 = np.ones((n + 1, 1)) 244 | mat3[n] = 0 245 | mat3 = tf.constant(mat3) 246 | mat4 = np.zeros((n + 1, 1)) 247 | mat4[n] = 1 248 | mat4 = tf.constant(mat4) 249 | 250 | kmat_ = layers.Input(shape=(n + 1, n + 1)) 251 | if variogramLayer != None and variogramLayer.__class__ == NestVariogramLayer: 252 | mvec_ = layers.Input(shape=(n + 1, vecDim)) 253 | else: 254 | mvec_ = layers.Input(shape=(n + 1,)) 255 | pro = layers.Input(shape=(n,)) 256 | if variogramLayer != None: 257 | mvec = variogramLayer(mvec_) 258 | mvec = layers.Reshape((n + 1, 1))(mvec) 259 | 260 | kmat = kmat_ 261 | kmat = kmat * mat1 262 | kmat = kmat + mat2 263 | mvec = mvec * mat3 264 | mvec = mvec + mat4 265 | else: 266 | kmat = kmat_ 267 | mvec = mvec_ 268 | mvec = layers.Reshape((n + 1, 1))(mvec) 269 | kmatInv = InvLayer()(kmat) 270 | lambvec = layers.Dot(1)([kmatInv, mvec]) 271 | estimate = layers.Dot(1)([pro, lambvec[:, :n]]) 272 | 273 | lambvec = layers.Reshape((n + 1,))(lambvec) 274 | mvec = layers.Reshape((n + 1,))(mvec) 275 | sigma = layers.Dot(1)([lambvec, mvec]) 276 | model = Model(inputs=[kmat_, mvec_, pro], outputs=[estimate, sigma]) 277 | return model 278 | 279 | 280 | class TFOK: 281 | ''' 282 | Tensorflow version of Ordinary Kriging interpolator. 283 | ''' 284 | 285 | def __init__(self, samples, mode='2d'): 286 | ''' 287 | Initialize the interpolator using sample points. 288 | 289 | :param samples: ndarray, array containing all sample points. The last column must be the properties. 290 | For the case of two-dimensional interpolation, where each item is represented by [x,y,property]. 291 | For the case of three-dimensional interpolation, where each item is represented by [x,y,z,property]. 292 | :param mode: str, '2d' or '3d'. 293 | ''' 294 | self.samples = samples 295 | self.mode = mode 296 | self._i = 2 297 | if mode.lower() == '3d': 298 | self._i = 3 299 | self.innerVecs = None 300 | 301 | def execute(self, points, N=8, variogramLayer=None, batch_size=10000): 302 | ''' 303 | Perform interpolation for points and return result values. 304 | 305 | :param points: ndarray, array containing all the coordinate points to be interpolated. 306 | :param N: integer, neighborhood size. 307 | :param variogramLayer: keras' layer, layer representing a variogram function. 308 | :param batch_size: integer, size of each batch of data to be calculated. 309 | :return: tuple, tuple containing tow ndarray. 310 | The first ndarray representing the interpolation result, 311 | the second ndarray representing the kriging variance. 312 | ''' 313 | self.N = N 314 | self.model = OKModel(N, variogramLayer, self._i) 315 | isNest = variogramLayer.__class__ == NestVariogramLayer 316 | if self.innerVecs is None: 317 | self.__calcInnerVecs__() 318 | if variogramLayer is None: 319 | self.innerVars = np.linalg.norm(self.innerVecs, axis=2) 320 | elif isNest: 321 | self.innerVars = variogramLayer(self.innerVecs).numpy() 322 | else: 323 | self.innerVars = np.linalg.norm(self.innerVecs, axis=2) 324 | self.innerVars = variogramLayer(self.innerVars).numpy() 325 | if self.innerVars.shape[-1] == 1: 326 | self.innerVars = self.innerVars.reshape(self.innerVars.shape[:-1]) 327 | 328 | tree = cKDTree(self.samples[:, :self._i]) 329 | step = batch_size * 3 330 | num = int(np.ceil(len(points) / step)) 331 | pros = np.empty((0, 1)) 332 | sigmas = np.empty((0, 1)) 333 | init = False 334 | for i in range(num): 335 | begin = i * step 336 | end = (i + 1) * step 337 | if end > len(points): 338 | end = len(points) 339 | if not init or i == num - 1: 340 | kmatArr = np.ones((end - begin, N + 1, N + 1)) 341 | for j in range(end - begin): 342 | kmatArr[j, N, N] = 0.0 343 | if isNest: 344 | mvecArr = np.zeros((end - begin, N + 1, self._i)) 345 | else: 346 | mvecArr = np.ones((end - begin, N + 1)) 347 | neighProArr = np.zeros((end - begin, N)) 348 | init = True 349 | points_ = points[begin:end] 350 | nbd, nbIdx = tree.query(points_, k=self.N, eps=0.0) 351 | for idx, indice in enumerate(nbIdx): 352 | kmatArr[idx, :N, :N] = self.innerVars[indice][:, indice] 353 | if isNest: 354 | mvecArr[idx, :N] = self.samples[indice, :self._i] - points_[idx] 355 | else: 356 | mvecArr[idx, :N] = nbd[idx] 357 | neighProArr[idx] = self.samples[indice, self._i] 358 | pro, sigma = self.model.predict([kmatArr, mvecArr, neighProArr], batch_size=batch_size) 359 | pros = np.append(pros, pro) 360 | sigmas = np.append(sigmas, sigma) 361 | return pros, sigmas 362 | 363 | def crossValidateKFold(self, K=10, N=8, variogramLayer=None): 364 | ''' 365 | Perform k-fold cross validation on sample points. 366 | 367 | :param K: integer. 368 | :param N: integer, neighborhood size. 369 | :param variogramLayer: keras' layer, layer representing a variogram function. 370 | :return: tuple, tuple containing three list. 371 | The first list contains the absolute mean error for each fold, 372 | the second list contains the absolute standard deviation error for each fold, 373 | the last list contains the origin error for each fold. 374 | ''' 375 | splits = kSplit(self.samples, K) 376 | absErrorMeans = [] 377 | absErrorStds = [] 378 | originalErrorList = [] 379 | for i in range(K): 380 | concatenateList = [] 381 | for j in range(K): 382 | if j == i: 383 | continue 384 | concatenateList.append(splits[j]) 385 | p1 = np.concatenate(concatenateList) 386 | p2 = splits[i] 387 | if len(p2) == 0: 388 | break 389 | exe = TFOK(p1, self.mode) 390 | es, _ = exe.execute(p2[:, :self._i], N, variogramLayer) 391 | error = p2[:, self._i] - es 392 | absError = np.abs(error) 393 | mean = absError.mean() 394 | std = absError.std() 395 | originalErrorList.extend(error.reshape(-1).tolist()) 396 | absErrorMeans.append(mean) 397 | absErrorStds.append(std) 398 | return absErrorMeans, absErrorStds, originalErrorList 399 | 400 | def crossValidate(self, N=8, variogramLayer=None): 401 | ''' 402 | Perform leave-one-out cross validation on sample points. 403 | 404 | :param N: integer, neighborhood size. 405 | :param variogramLayer: keras' layer, layer representing a variogram function. 406 | :return: tuple, tuple containing absolute mean error, absolute standard deviation error and origin error(ndarray). 407 | ''' 408 | self.N = N 409 | self.model = OKModel(N, variogramLayer, self._i) 410 | isNest = variogramLayer.__class__ == NestVariogramLayer 411 | if self.innerVecs is None: 412 | self.__calcInnerVecs__() 413 | if variogramLayer is None: 414 | self.innerVars = np.linalg.norm(self.innerVecs, axis=2) 415 | elif isNest: 416 | self.innerVars = variogramLayer(self.innerVecs).numpy() 417 | else: 418 | self.innerVars = np.linalg.norm(self.innerVecs, axis=2) 419 | self.innerVars = variogramLayer(self.innerVars).numpy() 420 | if self.innerVars.shape[-1] == 1: 421 | self.innerVars = self.innerVars.reshape(self.innerVars.shape[:-1]) 422 | 423 | tree = cKDTree(self.samples[:, :self._i]) 424 | nbd, nbIdx = tree.query(self.samples[:, :self._i], k=N + 1, eps=0.0) 425 | L = len(self.samples) 426 | kmatArr = np.ones((L, N + 1, N + 1)) 427 | for j in range(L): 428 | kmatArr[j, N, N] = 0.0 429 | if isNest: 430 | mvecArr = np.zeros((L, N + 1, self._i)) 431 | else: 432 | mvecArr = np.ones((L, N + 1)) 433 | neighProArr = np.zeros((L, N)) 434 | for idx, indice in enumerate(nbIdx): 435 | indice = indice[1:] 436 | kmatArr[idx, :N, :N] = self.innerVars[indice][:, indice] 437 | if isNest: 438 | mvecArr[idx, :N] = self.samples[indice, :self._i] - self.samples[idx, :self._i] 439 | else: 440 | mvecArr[idx, :N] = nbd[idx][1:] 441 | neighProArr[idx] = self.samples[indice, self._i] 442 | pros, _ = self.model.predict([kmatArr, mvecArr, neighProArr], batch_size=10000) 443 | pros = pros.reshape(-1) 444 | error = pros - self.samples[:, self._i] 445 | absError = np.abs(error) 446 | mean = absError.mean() 447 | std = absError.std() 448 | return mean, std, error 449 | 450 | def __calcInnerVecs__(self): 451 | ''' 452 | Compute vectors between sample points. 453 | 454 | :return: None. 455 | ''' 456 | innerVecs = calcVecs(self.samples[:, :self._i], includeSelf=True) 457 | self.innerVecs = innerVecs.reshape((self.samples.shape[0], self.samples.shape[0], self._i)) 458 | -------------------------------------------------------------------------------- /src/tfinterpy/tf/variogramLayer.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | from tensorflow.keras import layers 3 | 4 | tf.keras.backend.set_floatx('float64') 5 | 6 | class LinearLayer(layers.Layer): 7 | ''' 8 | The keras layer representing the linear variogram function model. 9 | ''' 10 | 11 | def __init__(self, slope, C0): 12 | super(LinearLayer, self).__init__() 13 | self.slope = tf.constant(slope) 14 | self.C0 = tf.constant(C0) 15 | 16 | def call(self, h): 17 | return h * self.slope + self.C0 18 | 19 | 20 | class PowerLayer(layers.Layer): 21 | ''' 22 | The keras layer representing the power variogram function model. 23 | ''' 24 | 25 | def __init__(self, scale, exp, C0): 26 | super(PowerLayer, self).__init__() 27 | self.scale = tf.constant(scale) 28 | self.exp = tf.constant(exp) 29 | self.C0 = tf.constant(C0) 30 | 31 | def call(self, h): 32 | return self.scale * (h ** self.exp) + self.C0 33 | 34 | 35 | class GaussianLayer(layers.Layer): 36 | ''' 37 | The keras layer representing the gaussian variogram function model. 38 | ''' 39 | 40 | def __init__(self, C, a, C0): 41 | super(GaussianLayer, self).__init__() 42 | self.C = tf.constant(C) 43 | self.a_2 = tf.constant((a * 4 / 7) ** 2) 44 | self.C0 = tf.constant(C0) 45 | 46 | def call(self, h): 47 | return self.C * (1.0 - tf.exp(-1.0 * (h ** 2.0) / self.a_2)) + self.C0 48 | 49 | 50 | class ExponentLayer(layers.Layer): 51 | ''' 52 | The keras layer representing the exponent variogram function model. 53 | ''' 54 | 55 | def __init__(self, C, a, C0): 56 | super(ExponentLayer, self).__init__() 57 | self.C = tf.constant(C) 58 | self.a_ = tf.constant(a / 3.0) 59 | self.C0 = tf.constant(C0) 60 | 61 | def call(self, h): 62 | return self.C * (1.0 - tf.exp(-1.0 * h / self.a_)) + self.C0 63 | 64 | 65 | class SphericalLayer(layers.Layer): 66 | ''' 67 | The keras layer representing the spherical variogram function model. 68 | ''' 69 | 70 | def __init__(self, C, a, C0): 71 | super(SphericalLayer, self).__init__() 72 | self.C = tf.constant(C) 73 | self.a = tf.constant(a) 74 | self.a2 = tf.constant(2 * a) 75 | self.a2_3 = tf.constant(2 * self.a ** 3) 76 | self.C0 = tf.constant(C0) 77 | 78 | def call(self, h): 79 | condition = tf.greater(h, self.a) 80 | return tf.where(condition, self.C + self.C0, self.C * (h * 3.0 / self.a2 - h ** 3.0 / self.a2_3) + self.C0) 81 | 82 | 83 | class NestVariogramLayer(layers.Layer): 84 | ''' 85 | The keras layer representing the nested variogram functions. 86 | ''' 87 | 88 | def __init__(self, variogramLayers, unitVectors): 89 | ''' 90 | Construct a nested variogram function layer. 91 | 92 | :param variogramLayers: list, containing variogram layers. 93 | :param unitVectors: array_like, unit vectors corresponding to the direction. 94 | ''' 95 | super(NestVariogramLayer, self).__init__() 96 | self.variogramLayers = variogramLayers 97 | self.unitVectors = unitVectors 98 | if len(self.unitVectors.shape) == 2: 99 | self.unitVectors = self.unitVectors.reshape((*self.unitVectors.shape, 1)) 100 | 101 | def call(self, vec): 102 | total = 0 103 | for idx, variogramLayer in enumerate(self.variogramLayers): 104 | h = tf.abs(tf.matmul(vec, self.unitVectors[idx])) 105 | var = variogramLayer(h) 106 | total += var 107 | return total 108 | 109 | 110 | VariogramLayerMap = { 111 | "gaussian": GaussianLayer, 112 | "exponent": ExponentLayer, 113 | "spherical": SphericalLayer, 114 | "linear": LinearLayer, 115 | "power": PowerLayer, 116 | } 117 | 118 | 119 | def getVariogramLayer(variogramBuilder): 120 | ''' 121 | Construct variogram layer by variogram builder. 122 | 123 | :param variogramBuilder: VariogramBuilder object. 124 | :return: keras' layer object. 125 | ''' 126 | LayerClass = VariogramLayerMap[variogramBuilder.model] 127 | vl = LayerClass(*variogramBuilder.params) 128 | return vl 129 | 130 | 131 | def getNestVariogramLayer(variogramBuilders, unitVectors): 132 | ''' 133 | Construct nested variogram layer by variogram builders and corresponding unit vectors. 134 | 135 | :param variogramBuilders: list, containing variogram builders. 136 | :param unitVectors: array_like, unit vectors corresponding to the direction. 137 | :return: keras' layer object. 138 | ''' 139 | vls = [] 140 | for vb in variogramBuilders: 141 | vl = getVariogramLayer(vb) 142 | vls.append(vl) 143 | return NestVariogramLayer(vls, unitVectors) 144 | -------------------------------------------------------------------------------- /src/tfinterpy/utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def h2(p1, p2): 5 | ''' 6 | Return the square of distance between p1 and p2. 7 | p1 and p2 can be either a one-dimensional array representing a single 8 | coordinate point or an ndarray containing multiple coordinate points. 9 | The shapes of p1 and p2 should be the same. 10 | 11 | :param p1: array_like. 12 | :param p2: array_like. 13 | :return: ndarray. 14 | ''' 15 | diff = np.square(np.subtract(p1, p2)) 16 | return np.sum(diff, axis=-1) 17 | 18 | 19 | def h(p1, p2): 20 | ''' 21 | Return the distance between p1 and p2. 22 | p1 and p2 can be either a one-dimensional array representing a single 23 | coordinate point or an ndarray containing multiple coordinate points. 24 | The shapes of p1 and p2 should be the same. 25 | 26 | :param p1: array_like. 27 | :param p2: array_like. 28 | :return: ndarray. 29 | ''' 30 | return np.sqrt(h2(p1, p2)) 31 | 32 | 33 | def ha(p1, p2): 34 | ''' 35 | Return the distance and angele between p1 and p2. 36 | p1 and p2 can be either a one-dimensional array representing a single 37 | coordinate point or an ndarray containing multiple coordinate points. 38 | The shapes of p1 and p2 should be the same. 39 | 40 | :param p1: array_like. 41 | :param p2: array_like. 42 | :return: tuple, tuple containing two ndarray. 43 | The first ndarray representing the distance, 44 | the second list representing the angle, the angle range is [0,PI]. 45 | ''' 46 | diff = np.subtract(p1, p2) 47 | h = np.sqrt(np.sum(np.square(diff), axis=-1)) 48 | if diff.ndim == 1: 49 | angle = np.arctan2(diff[1], diff[0]) 50 | angle = angle + np.pi if angle < 0 else angle 51 | else: 52 | angle = np.arctan2(diff[:, 1], diff[:, 0]) 53 | angle[angle < 0] += np.pi 54 | return h, angle 55 | 56 | 57 | def calcHV(data, dim=2, attrib_col=2): 58 | ''' 59 | Calculates the distance and variation between data. 60 | 61 | :param data: ndarray, array containing coordinates and attributes. 62 | :param dim: integer, indicates whether the coordinates are 2d or 3d. 63 | :param attrib_col: integer, indicates which column is property. 64 | :return: ndarray, the first column is distance, the second column is variation. 65 | ''' 66 | if dim == 3 and attrib_col < 3: 67 | attrib_col = 3 68 | arr = np.empty((0, 2), dtype="float32") 69 | size = data.shape[0] 70 | for i in range(size - 1): 71 | dis = h(data[i + 1:, :dim], data[i, :dim]) 72 | halfvar = 0.5 * ((data[i + 1:, attrib_col] - data[i, attrib_col]) ** 2) 73 | dis.resize((dis.shape[0], 1)) 74 | halfvar.resize((halfvar.shape[0], 1)) 75 | arr = np.append(arr, np.concatenate([dis, halfvar], axis=1), axis=0) 76 | return arr 77 | 78 | 79 | def calcHAV(data, attrib_col=2): 80 | ''' 81 | Calculates the distance, angle and variation between data. 82 | 83 | :param data: ndarray, array containing coordinates and attributes. 84 | :param attrib_col: integer, indicates which column is property. 85 | :return: ndarray, the first column is distance, 86 | the second column is angle (range is [0, PI]), 87 | the third column is variation. 88 | ''' 89 | dim = 2 90 | if attrib_col < 2: 91 | attrib_col = 2 92 | arr = np.empty((0, 3), dtype="float32") 93 | size = data.shape[0] 94 | for i in range(size - 1): 95 | dis, angle = ha(data[i + 1:, :dim], data[i, :dim]) 96 | halfvar = 0.5 * ((data[i + 1:, attrib_col] - data[i, attrib_col]) ** 2) 97 | dis.resize((dis.shape[0], 1)) 98 | angle.resize((angle.shape[0], 1)) 99 | halfvar.resize((halfvar.shape[0], 1)) 100 | arr = np.append(arr, np.concatenate([dis, angle, halfvar], axis=1), axis=0) 101 | return arr 102 | 103 | 104 | def calcHAVByVecs(vecs): 105 | ''' 106 | Calculates the distance, angle and variation according to vectors. 107 | 108 | :param vecs: ndarray, vectors containing 2d coordinates' difference and properties' difference. 109 | :return: ndarray, the first column is distance, 110 | the second column is angle (range is [0, PI]), 111 | the third column is variation. 112 | ''' 113 | distance = np.linalg.norm(vecs[:, :2], axis=1) 114 | angle = np.arctan2(vecs[:, 1], vecs[:, 0]) 115 | angle[angle < 0] += np.pi 116 | var = 0.5 * (vecs[:, 2] ** 2) 117 | hav = np.zeros((len(vecs), 3)) 118 | hav[:, 0] = distance 119 | hav[:, 1] = angle 120 | hav[:, 2] = var 121 | return hav 122 | 123 | 124 | def calcHABVByVecs(vecs): 125 | ''' 126 | Calculates the distance, azimuth(alpha), dip(beta) and variation according to vectors. 127 | 128 | :param vecs: ndarray, vectors containing 3d coordinates' difference and properties' difference. 129 | :return: ndarray, the first column is distance, 130 | the second column is azimuth(alpha) (range is [0, PI]), 131 | the second column is dip(beta) (range is [0, PI]), 132 | the fourth column is variation. 133 | ''' 134 | distance = np.linalg.norm(vecs[:, :3], axis=1) 135 | azimuth = np.arctan2(vecs[:, 1], vecs[:, 0]) 136 | azimuth[azimuth < 0] += np.pi 137 | norm = np.linalg.norm(vecs[:, :2], axis=1) 138 | dip = np.arctan2(vecs[:, 2], norm) 139 | dip[dip < 0] += np.pi 140 | var = 0.5 * (vecs[:, 3] ** 2) 141 | habv = np.zeros((len(vecs), 4)) 142 | habv[:, 0] = distance 143 | habv[:, 1] = azimuth 144 | habv[:, 2] = dip 145 | habv[:, 3] = var 146 | return habv 147 | 148 | 149 | def calcVecs(data, includeSelf=False, repeat=True): 150 | ''' 151 | Compute vectors between data. 152 | 153 | :param data: ndarray, two-dimensional array. 154 | :param includeSelf: boolean, whether to subtract the vector from itself. 155 | :param repeat: boolean, whether to calculate the two points that have subtracted from each other. 156 | :return: ndarray, vectors. 157 | ''' 158 | L = len(data) 159 | if repeat: 160 | vecs = [] 161 | if includeSelf: 162 | for i in range(L): 163 | vec = data - data[i] 164 | vecs.append(vec) 165 | else: 166 | _indice = [i for i in range(L)] 167 | for i in range(L): 168 | indice = list(_indice) 169 | indice.pop(i) 170 | vec = data[indice] - data[i] 171 | vecs.append(vec) 172 | vecs = np.array(vecs) 173 | return vecs.reshape((vecs.shape[0] * vecs.shape[1], vecs.shape[2])) 174 | else: 175 | vecs = np.empty((0, data.shape[1])) 176 | for i in range(L - 1): 177 | vec = data[i + 1:] - data[i] 178 | vecs = np.append(vecs, vec, axis=0) 179 | return vecs 180 | 181 | 182 | def kSplit(ndarray, k): 183 | ''' 184 | Split the ndarray into k fold. 185 | 186 | :param ndarray: ndarray. 187 | :param k: integer, fold number. 188 | :return: list, list containing all fold. 189 | ''' 190 | size = ndarray.shape[0] 191 | step = size // k 192 | if size % k != 0: 193 | step += 1 194 | splits = [] 195 | for i in range(k): 196 | begin = int(i * step) 197 | end = int((i + 1) * step) 198 | if i == k - 1: 199 | splits.append(ndarray[begin:]) 200 | else: 201 | splits.append(ndarray[begin:end]) 202 | return splits 203 | -------------------------------------------------------------------------------- /src/tfinterpy/variogram.py: -------------------------------------------------------------------------------- 1 | from tfinterpy.utils import * 2 | from tfinterpy.variogramExp import search2d, search3d 3 | from tfinterpy.variogramModel import variogramModel, VariogramModelMap 4 | from scipy.optimize import least_squares 5 | 6 | EPS = 1e-16 7 | 8 | def resident(params, x, y, variogram_function): 9 | ''' 10 | This function is used to calculate resident. 11 | 12 | :param params: tuple, represents the parameters passed to the variogram function. 13 | :param x: number or ndarray, distance. 14 | :param y: number or ndarray, semivariance. 15 | :param variogram_function: function, variogram function. 16 | :return: number or ndarray, resident=( variogram(x,params[0],...,params[n])-y )^2 17 | ''' 18 | error = variogram_function(x, *params) - y 19 | return error ** 2 20 | 21 | 22 | def getX0AndBnds(h, y, variogram_model): 23 | ''' 24 | Calculate the initial value and range of parameters(nugget, sill, range, ...) 25 | according to the variogram function model. 26 | 27 | :param h: array_like, distance. 28 | :param y: array_like, semivariance. 29 | :param variogram_model: str, indicates the variogram function model. 30 | :return: tuple, (x0,bnds). x0 represents the initial value of the parameters, 31 | and bnds represents the range of the parameters. 32 | ''' 33 | if variogram_model == "linear": 34 | x0 = [(np.amax(y) - np.amin(y)) / 2 / (np.amax(h) - np.amin(h)), np.amin(y)] 35 | bnds = ([0.0, 0.0], [np.inf, np.amax(y)]) 36 | elif variogram_model == "power": 37 | x0 = [(np.amax(y) - np.amin(y)) / (np.amax(h) - np.amin(h)), 1.0, np.amin(y)] 38 | bnds = ([0.0, 0.001, 0.0], [np.inf, 1.999, np.amax(y)]) 39 | else: 40 | x0 = [(np.amax(y) - np.amin(y)) / 2, 0.5 * np.amax(h), np.amin(y)] 41 | bnds = ([0.0, 0.0, 0.0], [np.amax(y), np.amax(h), np.amax(y)]) 42 | return x0, bnds 43 | 44 | 45 | class VariogramBuilder: 46 | ''' 47 | VariogramBuilder class is used to build variogram function. 48 | ''' 49 | 50 | def __init__(self, lags, model="spherical"): 51 | ''' 52 | The VariogramBuilder is constructed with lags and string indicating the model. 53 | 54 | :param lags: array_like, a lag is [distance,semivariance]. 55 | :param model: str, indicates the variogram function model. 56 | ''' 57 | self.model = model 58 | self.lags = np.array(lags) 59 | x0, bnds = getX0AndBnds(self.lags[:, 0], self.lags[:, 1], model) 60 | res = least_squares(resident, x0, bounds=bnds, loss="huber", 61 | args=(self.lags[:, 0], self.lags[:, 1], variogramModel(model))) 62 | self.params = res.x 63 | self.mae = np.mean(res.fun) 64 | 65 | def showVariogram(self, axes=None): 66 | ''' 67 | Plot variogram. 68 | 69 | :param axes: axes, if axes is set to None, plot on a new axes. 70 | :return: None. 71 | ''' 72 | if axes is None: 73 | import matplotlib.pyplot as axes 74 | variogram = self.getVariogram() 75 | axes.scatter(self.lags[:, 0], self.lags[:, 1], alpha=0.5) 76 | max = np.max(self.lags[:, 0]) 77 | X = np.arange(0, max, max / 100) 78 | Y = variogram(X) 79 | axes.plot(X, Y, alpha=0.5, color="red", label=self.model) 80 | 81 | def getVariogram(self): 82 | ''' 83 | Get variogram function(closure function). 84 | :return: function. 85 | ''' 86 | def variogram(h): 87 | return variogramModel(self.model)(h, *self.params) 88 | return variogram 89 | 90 | 91 | class NestVariogram: 92 | ''' 93 | NestVariogram class is used to calculate the nesting variogram function value. 94 | A NestVariogram object is a functor. 95 | ''' 96 | 97 | def __init__(self, variograms, unitVectors): 98 | ''' 99 | The nested variational function object is constructed by 100 | using a number of unit vectors and variograms calculated 101 | from different directions. 102 | 103 | :param variograms: list, variogram functions. 104 | :param unitVectors: array_like, unit vectors corresponding to the direction. 105 | ''' 106 | self.variograms = variograms 107 | self.unitVectors = unitVectors 108 | 109 | def __call__(self, vec): 110 | ''' 111 | Calculate the value of the nesting variogram function. 112 | 113 | :param vec: array_like, vectors. 114 | :return: array_like, variogram function value. 115 | ''' 116 | totalVar = 0 117 | for idx, unitVector in enumerate(self.unitVectors): 118 | h = np.abs(np.dot(vec, unitVector)) 119 | var = self.variograms[idx](h) 120 | totalVar += var 121 | return totalVar 122 | 123 | 124 | def calculateOmnidirectionalVariogram2D(samples, partitionNum=8, leastPairNum=10, lagNum=20, lagInterval=None, 125 | lagTole=None, bandWidth=None, model=None): 126 | ''' 127 | Calculating the omnidirectional variogram in two dimensions. 128 | 129 | :param samples: ndarray, array containing all sample points. The last column must be the properties. 130 | Each item is represented by [x,y,property]. 131 | 132 | :param partitionNum: integer, indicates how many parts the angle range is divided into. 133 | :param leastPairNum: integer, at least lastPairNum lags need to be searched 134 | in one direction to fit the variogram function. 135 | :param lagNum: integer, number of lags to search. 136 | :param lagInterval: number, interval lags' distance. 137 | If lagInterval is set to None, then it is set to 0.75 times. 138 | the maximum vector modulus length divided by lagNum. 139 | :param lagTole: number, tolerance of lag's distance. 140 | If lagTole is set to None, then it is set to lagInterval/2. 141 | :param bandWidth: number, bandwidth used during search. 142 | If bandWidth is set to None, then it is set to the mean 143 | of the vector modulus length divided by 2. 144 | :param model: str, specify which variogram function model to use for the fit. 145 | If model is set to None, fitting will be attempted using all the variogram 146 | function models in the variogramModel module, and the best fit will be used. 147 | :return: tuple, (NestVariogram,variogramBuilders). 148 | NestVariogram is NestVariogram object, 149 | variogramBuilders is a list of VariogramBuilder objects corresponding to 150 | all variogram functions maintained within the NestVariogram object. 151 | ''' 152 | vecs = calcVecs(samples, repeat=False) 153 | vars = 0.5 * vecs[:, 2] ** 2 154 | vecs = vecs[:, :2] 155 | azimuthStep = np.pi / partitionNum 156 | unitVectors = [] 157 | azimuths = [] 158 | for i in range(partitionNum): 159 | azimuth = (i + 0.5) * azimuthStep 160 | azimuths.append(azimuth) 161 | unitVectors.append([np.cos(azimuth), np.sin(azimuth)]) 162 | unitVectors = np.array(unitVectors) 163 | azimuths = np.array(azimuths) 164 | norms = np.linalg.norm(vecs, axis=1) + EPS 165 | if bandWidth is None: 166 | bandWidth = norms.mean() / 2 167 | if lagInterval is None: 168 | lagInterval = norms.max() * 0.75 / lagNum 169 | if lagTole is None: 170 | lagTole = lagInterval / 2 171 | lagRanList = [[(i + 1) * lagInterval - lagTole, (i + 1) * lagInterval + lagTole] for i in range(lagNum)] 172 | bucket = [[[] for j in range(lagNum)] for i in range(partitionNum)] 173 | thetas = np.arctan2(vecs[:, 1], vecs[:, 0]) 174 | thetas[thetas < 0] += np.pi 175 | indiceTheta = thetas // azimuthStep 176 | indiceTheta = indiceTheta.astype('int') 177 | for i in range(partitionNum): 178 | deltas = thetas - azimuths[i] 179 | bands = norms * deltas 180 | for j in range(lagNum): 181 | indice = np.where( 182 | ((indiceTheta == i) & (norms > lagRanList[j][0]) & (norms < lagRanList[j][1]) & (bands < bandWidth)))[0] 183 | bucket[i][j] = list(zip(norms[indice], vars[indice])) 184 | processedBucket = [[] for i in range(partitionNum)] 185 | searchedPairNumRecords = [[] for i in range(partitionNum)] 186 | for i in range(partitionNum): 187 | for j in range(lagNum): 188 | searchedPairNum = len(bucket[i][j]) 189 | if searchedPairNum < 3: 190 | continue 191 | searchedPairNumRecords[i].append(searchedPairNum) 192 | lag = np.mean(bucket[i][j], axis=0) 193 | processedBucket[i].append(lag) 194 | lagsList = [None for i in range(partitionNum)] 195 | availableDir = [] 196 | for i in range(partitionNum): 197 | if len(processedBucket[i]) > leastPairNum: 198 | lagsList[i] = processedBucket[i] 199 | availableDir.append(i) 200 | variogramBuilders = [] 201 | if model is None: 202 | for lags in lagsList: 203 | if lags is None: 204 | continue 205 | minResident = float('+inf') 206 | best = None 207 | for key in VariogramModelMap: 208 | vb = VariogramBuilder(lags, key) 209 | if vb.mae < minResident: 210 | minResident = vb.mae 211 | best = vb 212 | variogramBuilders.append(best) 213 | else: 214 | for lags in lagsList: 215 | if lags is None: 216 | continue 217 | vb = VariogramBuilder(lags, model) 218 | variogramBuilders.append(vb) 219 | nestVariogram = NestVariogram([vb.getVariogram() for vb in variogramBuilders], unitVectors[availableDir]) 220 | return nestVariogram, variogramBuilders 221 | 222 | 223 | def calculateOmnidirectionalVariogram3D(samples, partitionNum=[6, 6], leastPairNum=10, lagNum=20, lagInterval=None, 224 | lagTole=None, bandWidth=None, model=None): 225 | ''' 226 | Calculating the omnidirectional variogram in three dimensions. 227 | 228 | :param samples: ndarray, array containing all sample points. The last column must be the properties. 229 | Each item is represented by [x,y,z,property]. 230 | :param partitionNum: array_like,Indicates how many parts the angle range 231 | in horizontal and vertical directions is divided into. 232 | :param leastPairNum: integer, at least lastPairNum lags need to be searched 233 | in one direction to fit the variogram function. 234 | :param lagNum: integer, number of lags to search. 235 | :param lagInterval: number, interval lags' distance. 236 | If lagInterval is set to None, then it is set to 0.75 times. 237 | :param lagTole: number, tolerance of lag's distance. 238 | If lagTole is set to None, then it is set to lagInterval/2. 239 | :param bandWidth: number, bandwidth used during search. 240 | If bandWidth is set to None, then it is set to the mean 241 | of the vector modulus length divided by 2. 242 | :param model: str, specify which variogram function model to use for the fit. 243 | If model is set to None, fitting will be attempted using all the variogram 244 | function models in the variogramModel module, and the best fit will be used. 245 | :return: tuple, (NestVariogram,variogramBuilders). 246 | NestVariogram is NestVariogram object, 247 | variogramBuilders is a list of VariogramBuilder objects corresponding to 248 | all variogram functions maintained within the NestVariogram object. 249 | ''' 250 | vecs = calcVecs(samples, repeat=False) 251 | vars = 0.5 * vecs[:, 3] ** 2 252 | vecs = vecs[:, :3] 253 | if type(partitionNum) != list: 254 | partitionNum = [partitionNum, partitionNum] 255 | azimuthStep = np.pi / partitionNum[0] 256 | azimuths = [(i + 0.5) * azimuthStep for i in range(partitionNum[0])] 257 | dipStep = np.pi / partitionNum[1] 258 | dips = [(i + 0.5) * dipStep for i in range(partitionNum[1])] 259 | unitVectors = [] 260 | for i in range(partitionNum[0]): 261 | a = azimuths[i] 262 | for j in range(partitionNum[1]): 263 | b = dips[j] 264 | unitVectors.append([np.cos(a) * np.cos(b), np.sin(a) * np.cos(b), np.sin(b)]) 265 | unitVectors = np.array(unitVectors) 266 | azimuths = np.array(azimuths) 267 | dips = np.array(dips) 268 | norms = np.linalg.norm(vecs, axis=1) + EPS 269 | if bandWidth is None: 270 | bandWidth = norms.mean() / 2 271 | if lagInterval is None: 272 | lagInterval = norms.max() * 0.75 / lagNum 273 | if lagTole is None: 274 | lagTole = lagInterval / 2 275 | lagRanList = [[(i + 1) * lagInterval - lagTole, (i + 1) * lagInterval + lagTole] for i in range(lagNum)] 276 | bucket = [[[[] for k in range(lagNum)] for j in range(partitionNum[1])] for i in range(partitionNum[0])] 277 | thetas1 = np.arctan2(vecs[:, 1], vecs[:, 0]) 278 | thetas1[thetas1 < 0] += np.pi 279 | thetas2 = np.arctan2(vecs[:, 2], np.linalg.norm(vecs[:, :2], axis=1)) 280 | thetas2[thetas2 < 0] += np.pi 281 | indiceTheta1 = thetas1 // azimuthStep 282 | indiceTheta1 = indiceTheta1.astype('int') 283 | indiceTheta2 = thetas2 // dipStep 284 | indiceTheta2 = indiceTheta2.astype('int') 285 | for i in range(partitionNum[0]): 286 | for j in range(partitionNum[1]): 287 | unitVector = unitVectors[i * partitionNum[1] + j] 288 | angles = np.arccos(np.dot(vecs, unitVector) / norms) 289 | indice = np.where(angles > np.pi / 2)[0] 290 | angles[indice] = np.pi - angles[indice] 291 | bands = norms * np.sin(angles) 292 | for k in range(lagNum): 293 | indice = np.where( 294 | ((indiceTheta1 == i) & (indiceTheta2 == j) & (norms > lagRanList[k][0]) & ( 295 | norms < lagRanList[k][1]) & (bands < bandWidth)))[0] 296 | bucket[i][j][k] = list(zip(norms[indice], vars[indice])) 297 | processedBucket = [[[] for j in range(partitionNum[1])] for i in range(partitionNum[0])] 298 | searchedPairNumRecords = [[[] for j in range(partitionNum[1])] for i in range(partitionNum[0])] 299 | for i in range(partitionNum[0]): 300 | for j in range(partitionNum[1]): 301 | for k in range(lagNum): 302 | searchedPairNum = len(bucket[i][j][k]) 303 | if searchedPairNum < 3: 304 | continue 305 | searchedPairNumRecords[i][j].append(searchedPairNum) 306 | lag = np.mean(bucket[i][j][k], axis=0) 307 | processedBucket[i][j].append(lag) 308 | lagsList = [None for i in range(partitionNum[0] * partitionNum[1])] 309 | availableDir = [] 310 | for i in range(partitionNum[0]): 311 | for j in range(partitionNum[1]): 312 | if len(processedBucket[i][j]) > leastPairNum: 313 | idx = i * partitionNum[1] + j 314 | lagsList[idx] = processedBucket[i][j] 315 | availableDir.append(idx) 316 | variogramBuilders = [] 317 | if model is None: 318 | for lags in lagsList: 319 | if lags is None: 320 | continue 321 | minResident = float('+inf') 322 | best = None 323 | for key in VariogramModelMap: 324 | vb = VariogramBuilder(lags, key) 325 | if vb.mae < minResident: 326 | minResident = vb.mae 327 | best = vb 328 | variogramBuilders.append(best) 329 | else: 330 | for lags in lagsList: 331 | if lags is None: 332 | continue 333 | vb = VariogramBuilder(lags, model) 334 | variogramBuilders.append(vb) 335 | nestVariogram = NestVariogram([vb.getVariogram() for vb in variogramBuilders], unitVectors[availableDir]) 336 | return nestVariogram, variogramBuilders 337 | 338 | 339 | def calculateDefaultVariogram2D(samples, model='spherical'): 340 | ''' 341 | Calculate the default variogram function in two dimensions, 342 | without considering the effect of direction. 343 | 344 | :param samples: ndarray, array containing all sample points. The last column must be the properties. 345 | Each item is represented by [x,y,property]. 346 | :param model: str, specify which variogram function model to use for the fit. 347 | :return: VariogramBuilder object. 348 | ''' 349 | vecs = calcVecs(samples, repeat=False) 350 | hav = calcHAVByVecs(vecs) 351 | lagNum = 20 352 | lagInterval = hav[:, 0].max() / 2 / lagNum 353 | lagTole = lagInterval * 0.5 354 | angles = hav[:, 1] 355 | buckets = [] 356 | portionNum = 8 357 | portion = np.pi / portionNum 358 | for i in range(portionNum): 359 | count = np.where((angles > portion * i) & (angles < portion * (i + 1)))[0].shape[0] 360 | buckets.append(count) 361 | idx = np.argmax(buckets) 362 | angle = portion * idx 363 | angleTole = portion 364 | bandWidth = hav[:, 0].mean() / 2 365 | lags, _ = search2d(vecs[:, :2], hav[:, 2], lagNum, lagInterval, lagTole, angle, angleTole, bandWidth) 366 | if len(lags) < 3: 367 | lags = calcHV(samples) 368 | vb = VariogramBuilder(lags, model) 369 | return vb 370 | 371 | 372 | def calculateDefaultVariogram3D(samples, model='spherical'): 373 | ''' 374 | Calculate the default variogram function in three dimensions, 375 | without considering the effect of direction. 376 | 377 | :param samples: ndarray, array containing all sample points. The last column must be the properties. 378 | Each item is represented by [x,y,z,property]. 379 | :param model: str, specify which variogram function model to use for the fit. 380 | :return: VariogramBuilder object. 381 | ''' 382 | vecs = calcVecs(samples, repeat=False) 383 | habv = calcHABVByVecs(vecs) 384 | lagNum = 20 385 | lagInterval = habv[:, 0].max() / 2 / lagNum 386 | lagTole = lagInterval * 0.5 387 | azimuths = habv[:, 1] 388 | dips = habv[:, 2] 389 | buckets = [] 390 | portionNum = 5 391 | portion = np.pi / portionNum 392 | for i in range(portionNum): 393 | for j in range(portionNum): 394 | count = np.where((azimuths > portion * i) & (azimuths < portion * (i + 1)) & (dips > portion * j) & ( 395 | dips < portion * (j + 1)))[0].shape[0] 396 | buckets.append(count) 397 | idx = np.argmax(buckets) 398 | azimuth = idx // portionNum * portion 399 | dip = idx % portionNum * portion 400 | angleTole = portion / 2 401 | bandWidth = habv[:, 0].mean() / 2 402 | lags, _ = search3d(vecs[:, :3], habv[:, 3], lagNum, lagInterval, lagTole, azimuth, dip, angleTole, bandWidth) 403 | if len(lags) < 3: 404 | lags = calcHV(samples) 405 | vb = VariogramBuilder(lags, model) 406 | return vb 407 | -------------------------------------------------------------------------------- /src/tfinterpy/variogramExp.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | EPS = 1e-16 4 | 5 | def search2d(vecs, vars, lagNum, lagInterval, lagTole, angle, angleTole, bandWidth): 6 | ''' 7 | Search for lags in two dimensions. 8 | 9 | :param vecs: ndarray, vectors. 10 | :param vars: ndarray, semivariance. 11 | :param lagNum: integer, number of lags to search. 12 | :param lagInterval: number, interval lags' distance. 13 | :param lagTole: number, tolerance of lag's distance. 14 | :param angle: number, search direction, angle range is [0, PI]. 15 | :param angleTole: number, angle tolerance. 16 | :param bandWidth: number, bandwidth used during search. 17 | :return: tuple, (processedLags, lags). 18 | processedLags is the mean-processed lags. 19 | lags is original searched lags. 20 | ''' 21 | unitVector = np.array([np.cos(angle), np.sin(angle)]) 22 | return searchLags(vecs, vars, lagNum, lagInterval, lagTole, unitVector, angleTole, bandWidth) 23 | 24 | 25 | def search3d(vecs, vars, lagNum, lagInterval, lagTole, azimuth, dip, angleTole, bandWidth): 26 | ''' 27 | 28 | :param vecs: ndarray, vectors. 29 | :param vars: ndarray, semivariance. 30 | :param lagNum: integer, number of lags to search. 31 | :param lagInterval: number, interval lags' distance. 32 | :param lagTole: number, tolerance of lag's distance. 33 | :param azimuth: number, azimuth of search direction, the range of azimuth is [0, PI]. 34 | :param dip: number, dip of search direction, the range of dip is [0, PI]. 35 | :param angleTole: number, angle tolerance. 36 | :param bandWidth: number, bandwidth used during search. 37 | :return: tuple, (processedLags, lags). 38 | processedLags is the mean-processed lags. 39 | lags is original searched lags. 40 | ''' 41 | unitVector = np.array([np.cos(azimuth) * np.cos(dip), np.sin(azimuth) * np.cos(dip), np.sin(dip)]) 42 | return searchLags(vecs, vars, lagNum, lagInterval, lagTole, unitVector, angleTole, bandWidth) 43 | 44 | 45 | def searchLags(vecs, vars, lagNum, lagInterval, lagTole, unitVector, angleTole, bandWidth): 46 | ''' 47 | Search lags. 48 | 49 | :param vecs: ndarray, vectors. 50 | :param vars: ndarray, semivariance. 51 | :param lagNum: integer, number of lags to search. 52 | :param lagInterval: number, interval lags' distance. 53 | :param lagTole: number, tolerance of lag's distance. 54 | :param unitVector: array_like, unit vector of search direction. 55 | :param angleTole: number, angle tolerance. 56 | :param bandWidth: number, bandwidth used during search. 57 | :return: tuple, (processedLags, lags). 58 | processedLags is the mean-processed lags. 59 | lags is original searched lags. 60 | ''' 61 | norms = np.linalg.norm(vecs, axis=1) + EPS 62 | thetas = np.arccos(np.dot(vecs, unitVector) / norms) 63 | indice = np.where(thetas > np.pi / 2)[0] 64 | thetas[indice] = np.pi - thetas[indice] 65 | # filter with angle 66 | remain = np.where(thetas <= angleTole)[0] 67 | norms = norms[remain] 68 | thetas = thetas[remain] 69 | vars = vars[remain] 70 | # filter with bandwith 71 | bands = norms * np.sin(thetas) 72 | remain = np.where(bands <= bandWidth)[0] 73 | norms = norms[remain] 74 | vars = vars[remain] 75 | # filter with lag range 76 | lagRanList = [] 77 | for i in range(1, lagNum + 1): 78 | lagRanList.append([lagInterval * i - lagTole, lagInterval * i + lagTole]) 79 | lags = [[] for i in range(lagNum)] 80 | for i in range(len(norms)): 81 | h = norms[i] 82 | for j in range(len(lagRanList)): 83 | if h > lagRanList[j][0] and h < lagRanList[j][1]: 84 | lags[j].append([h, vars[i]]) 85 | break 86 | processedLags = [] 87 | for ls in lags: 88 | if len(ls)==0: 89 | continue 90 | mean = np.mean(ls, axis=0) 91 | if np.isnan(mean).any(): 92 | continue 93 | processedLags.append(mean) 94 | return processedLags, lags 95 | -------------------------------------------------------------------------------- /src/tfinterpy/variogramModel.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def linear(h, slope, C0): 5 | ''' 6 | Linear model. 7 | 8 | :param h: number or ndarray, distance. 9 | :param slope: number. 10 | :param C0: number, nugget. 11 | :return: number or ndarray. 12 | ''' 13 | return slope * h + C0 14 | 15 | 16 | def power(h, scale, exp, C0): 17 | ''' 18 | Power model. 19 | 20 | :param h: number or ndarray, distance. 21 | :param scale: number. 22 | :param exp: number. 23 | :param C0: number, nugget. 24 | :return: number or ndarray. 25 | ''' 26 | return scale * (h ** exp) + C0 27 | 28 | 29 | def gaussian(h, C, a, C0): 30 | ''' 31 | Gaussian model. 32 | 33 | :param h: number or ndarray, distance. 34 | :param C: number, sill. 35 | :param a: number, range. 36 | :param C0: number, nugget. 37 | :return: number or ndarray. 38 | ''' 39 | return C * (1.0 - np.exp(-(h ** 2.0) / (a * 4.0 / 7.0) ** 2.0)) + C0 40 | 41 | 42 | def exponent(h, C, a, C0): 43 | ''' 44 | Exponent model. 45 | 46 | :param h: number or ndarray, distance. 47 | :param C: number, sill. 48 | :param a: number, range. 49 | :param C0: number, nugget. 50 | :return: number or ndarray. 51 | ''' 52 | return C * (1.0 - np.exp(-h / (a / 3.0))) + C0 53 | 54 | 55 | def spherical(h, C, a, C0): 56 | ''' 57 | Spherical model. 58 | 59 | :param h: number or ndarray, distance. 60 | :param C: number, sill. 61 | :param a: number, range. 62 | :param C0: number, nugget. 63 | :return: number or ndarray. 64 | ''' 65 | return np.piecewise(h, [h <= a, h > a], 66 | [lambda x: C * ((3.0 * x) / (2.0 * a) - (x ** 3.0) / (2.0 * a ** 3.0)) + C0, C + C0, ]) 67 | 68 | 69 | VariogramModelMap = { 70 | "spherical": spherical, 71 | "gaussian": gaussian, 72 | "exponent": exponent, 73 | "linear": linear, 74 | "power": power, 75 | } 76 | 77 | 78 | def variogramModel(name): 79 | ''' 80 | Returns the variogram function based on the name. 81 | 82 | :param name: str, variogram function name. 83 | :return: function. 84 | ''' 85 | func = VariogramModelMap.get(name) 86 | return func 87 | -------------------------------------------------------------------------------- /src/tfinterpy/vtk/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2022/3/28 12:03 3 | # @Author : UCCU 4 | -------------------------------------------------------------------------------- /src/tfinterpy/vtk/colorMap.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2022/3/25 20:05 3 | # @Author : UCCU 4 | 5 | import vtk 6 | 7 | CoolToWarm=[ 8 | [0.0,[0,0,255]], 9 | [0.5,[255,255,255]], 10 | [1.0,[255,0,0]], 11 | ] 12 | 13 | Rainbow=[ 14 | [0.0,[0,0,255]], 15 | [0.2,[0,127,255]], 16 | [0.4,[0,255,0]], 17 | [0.6,[255,255,0]], 18 | [0.8,[255,165,0]], 19 | [1.0,[255,0,0]] 20 | ] 21 | 22 | BlueGreenOrange=[ 23 | [0.0,[205,228,248]], 24 | [0.33,[29,65,88]], 25 | [0.66,[221,218,153]], 26 | [1.0,[115,2,0]] 27 | ] 28 | 29 | def getCTF(scalarMin,scalarMax,stops): 30 | ''' 31 | Get vtk color transfer function by scalarRange and stops. 32 | 33 | :param scalarMin: number. 34 | :param scalarMax: number. 35 | :param stops: list, each stop represented by [percentage,[r,g,b]]. 36 | :return: vtkDiscretizableColorTransferFunction object. 37 | ''' 38 | ctf=vtk.vtkDiscretizableColorTransferFunction() 39 | total=scalarMax-scalarMin 40 | 41 | for stop in stops: 42 | ctf.AddRGBPoint(scalarMin+total*stop[0],stop[1][0]/255.0,stop[1][1]/255.0,stop[1][2]/255.0) 43 | return ctf -------------------------------------------------------------------------------- /src/tfinterpy/vtk/fileUtils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2022/3/26 19:53 3 | # @Author : UCCU 4 | 5 | import vtk 6 | 7 | def saveVTKPoints(filePath,polyData): 8 | ''' 9 | Save vtkPoints to file. 10 | 11 | :param filePath: str. 12 | :param polyData: vtkPolyData object. 13 | :return: None. 14 | ''' 15 | writer=vtk.vtkPolyDataWriter() 16 | writer.SetFileName(filePath) 17 | writer.SetInputData(polyData) 18 | writer.Write() 19 | 20 | def saveVTKGrid(filePath,rectilinearGrid): 21 | ''' 22 | Save vtkRectilinearGrid to file. 23 | 24 | :param filePath: str. 25 | :param rectilinearGrid: vtkRectilinearGrid object. 26 | :return: None. 27 | ''' 28 | writer=vtk.vtkRectilinearGridWriter() 29 | writer.SetFileName(filePath) 30 | writer.SetInputData(rectilinearGrid) 31 | writer.SetWriteArrayMetaData(True) 32 | writer.Write() -------------------------------------------------------------------------------- /src/tfinterpy/vtk/rendering.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2022/3/28 12:08 3 | # @Author : UCCU 4 | import vtk 5 | import tfinterpy.vtk.colorMap as CM 6 | import numpy as np 7 | 8 | def createPointsActor(x,y,z=0,scalar=None,scalarRange=None,colorMap=CM.BlueGreenOrange): 9 | ''' 10 | Create vertices representing coordinate points based on the coordinate data. 11 | 12 | :param x: array_like, x coordinate data. 13 | :param y: array_like, y coordinate data. 14 | :param z: array_like, z coordinate data. 15 | If it is a two-dimensional space, z should be set to 0. 16 | :param scalar: array_like, properties. 17 | :param scalarRange: array_like, [scalarMin, scalarMax], properties' range. 18 | :param colorMap: list, refer to the colorMap in the vtk.colorMap module. 19 | :return: vtkActor object. 20 | ''' 21 | points = vtk.vtkPoints() 22 | L=len(x) 23 | points.SetNumberOfPoints(L) 24 | if z==0: 25 | for i in range(L): 26 | points.SetPoint(i,x[i],y[i],0) 27 | else: 28 | for i in range(L): 29 | points.SetPoint(i,x[i],y[i],z[i]) 30 | polyData = vtk.vtkPolyData() 31 | polyData.SetPoints(points) 32 | scalarRange=None 33 | if scalar is not None: 34 | scalarArr = vtk.vtkFloatArray() 35 | scalarArr.SetName("scalar") 36 | scalarArr.SetNumberOfComponents(1) 37 | scalarArr.SetNumberOfValues(L) 38 | for i in range(L): 39 | scalarArr.SetTuple1(i,scalar[i]) 40 | polyData.GetPointData().AddArray(scalarArr) 41 | polyData.GetPointData().SetActiveScalars("scalar") 42 | if scalarRange is None: 43 | scalarRange=[scalar.min(),scalar.max()] 44 | vertexGlyphFilter = vtk.vtkVertexGlyphFilter() 45 | vertexGlyphFilter.AddInputData(polyData) 46 | mapper = vtk.vtkPolyDataMapper() 47 | mapper.SetInputConnection(vertexGlyphFilter.GetOutputPort()) 48 | if scalarRange is not None: 49 | mapper.SetScalarRange(*scalarRange) 50 | ctf = CM.getCTF(scalarRange[0], scalarRange[1], colorMap) 51 | ctf.SetDiscretize(True) 52 | ctf.Build() 53 | mapper.SetLookupTable(ctf) 54 | actor = vtk.vtkActor() 55 | actor.SetMapper(mapper) 56 | actor.GetProperty().SetPointSize(5) 57 | return actor 58 | 59 | def createGridActor(nx,ny,nz,x,y,z,scalar=None,scalarRange=None,colorMap=CM.Rainbow): 60 | ''' 61 | Create rectilinear grid based on the coordinate data. 62 | 63 | :param nx: integer, number of x coordinate. 64 | :param ny: integer, number of y coordinate. 65 | :param nz: integer, number of z coordinate. 66 | :param x: array_like, x coordinate data. 67 | :param y: array_like, y coordinate data. 68 | :param z: array_like, z coordinate data. 69 | :param scalar: array_like, properties. 70 | :param scalarRange: array_like, [scalarMin, scalarMax], properties' range. 71 | :param colorMap: list, refer to the colorMap in the vtk.colorMap module. 72 | :return: vtkActor object. 73 | ''' 74 | rgrid = vtk.vtkRectilinearGrid() 75 | nz=1 if nz<=1 else nz 76 | z=[0] if nz==1 else z 77 | dim=[nx, ny, nz] 78 | rgrid.SetDimensions(dim) 79 | xcoords = vtk.vtkFloatArray() 80 | xcoords.SetNumberOfValues(dim[0]) 81 | xcoords.SetNumberOfComponents(1) 82 | ycoords = vtk.vtkFloatArray() 83 | ycoords.SetNumberOfValues(dim[1]) 84 | ycoords.SetNumberOfComponents(1) 85 | zcoords = vtk.vtkFloatArray() 86 | zcoords.SetNumberOfValues(dim[2]) 87 | zcoords.SetNumberOfComponents(1) 88 | for idx, value in enumerate(x): 89 | xcoords.SetValue(idx, value) 90 | for idx, value in enumerate(y): 91 | ycoords.SetValue(idx, value) 92 | for idx, value in enumerate(z): 93 | zcoords.SetValue(idx, value) 94 | rgrid.SetXCoordinates(xcoords) 95 | rgrid.SetYCoordinates(ycoords) 96 | rgrid.SetZCoordinates(zcoords) 97 | if scalar is not None: 98 | scalarArr = vtk.vtkFloatArray() 99 | scalarArr.SetName('scalar') 100 | scalarArr.SetNumberOfComponents(1) 101 | scalarArr.SetNumberOfValues(len(scalar)) 102 | for idx,value in enumerate(scalar): 103 | scalarArr.SetValue(idx,value) 104 | rgrid.GetPointData().AddArray(scalarArr) 105 | rgrid.GetPointData().SetActiveScalars("scalar") 106 | if scalarRange is None: 107 | scalarRange = [np.percentile(scalar,1), np.percentile(scalar,99)] 108 | mapper = vtk.vtkDataSetMapper() 109 | mapper.SetInputData(rgrid) 110 | if scalarRange is not None: 111 | mapper.SetScalarRange(*scalarRange) 112 | ctf = CM.getCTF(scalarRange[0], scalarRange[1], colorMap) 113 | ctf.SetDiscretize(True) 114 | ctf.Build() 115 | mapper.SetLookupTable(ctf) 116 | actor = vtk.vtkActor() 117 | actor.SetMapper(mapper) 118 | actor.GetProperty().SetInterpolationToGouraud() 119 | return actor 120 | 121 | def rendering(actor): 122 | ''' 123 | Create a new render window to render the actor. 124 | 125 | :param actor: vtkActor object. 126 | :return: None. 127 | ''' 128 | ren = vtk.vtkRenderer() 129 | ren.AddActor(actor) 130 | renWin = vtk.vtkRenderWindow() 131 | renWin.AddRenderer(ren) 132 | iren = vtk.vtkRenderWindowInteractor() 133 | iren.SetRenderWindow(renWin) 134 | ren.SetBackground(0.447, 0.552, 0.756) 135 | renWin.SetSize(960, 680) 136 | iren.Initialize() 137 | ren.ResetCamera() 138 | renWin.Render() 139 | iren.Start() --------------------------------------------------------------------------------