Module conduction.inversion.covariance
Copyright 2017 Ben Mather
This file is part of Conduction https://git.dias.ie/itherc/conduction/
Conduction is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version.
Conduction is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with Conduction. If not, see http://www.gnu.org/licenses/.
Expand source code
"""
Copyright 2017 Ben Mather
This file is part of Conduction <https://git.dias.ie/itherc/conduction/>
Conduction is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or any later version.
Conduction is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Conduction. If not, see <http://www.gnu.org/licenses/>.
"""
try: range=xrange
except: pass
import numpy as np
from mpi4py import MPI
comm = MPI.COMM_WORLD
def gaussian(sigma, distance, length_scale):
"""
Gaussian function
"""
return sigma**2 * np.exp(-distance**2/(2.0*length_scale**2))
def create_covariance_matrix(sigma, coords, max_dist, func, *args, **kwargs):
"""
Create a covariance matrix based on distance.
Euclidean distance between a set of points is queried from a KDTree
where max_dist sets the maximum radius between points to cut-off.
Parameters
----------
sigma : values of uncertainty for each point
coords : coordindates in n-dimensions for each point
max_dist : maximum radius to search for points
func : covariance function (default is Gaussian)
(pass a length parameter if using default)
args : arguments to pass to func
kwargs : keyword arguments to pass to func
Returns
-------
mat : covariance matrix
Notes
-----
Increasing max_dist increases the number of nonzeros in the
covariance matrix.
func should always receive sigma and distance as first
two inputs
"""
from scipy.spatial import cKDTree
from petsc4py import PETSc
ncov = len(sigma)
nn = np.hstack(sigma).size
if ncov < nn:
# this means we have a piecewise covariance matrix
if len(coords) != ncov or len(max_dist) != ncov:
raise ValueError("sigma, coords, max_dist must be the same dimensions")
# find the size of each list
size = np.zeros(ncov, dtype=PETSc.IntType)
nnz = []
for j in range(0,ncov):
size[j] = len(sigma[j])
dist = np.linalg.norm(coords[j] - coords[j].mean(axis=0), axis=1)
nnz_j = int(1.5*(dist <= max(max_dist[j])).sum())
nnz.append( np.ones(size[j], dtype=PETSc.IntType)*nnz_j )
nnz = np.clip(np.hstack(nnz), 1, 99999)
elif ncov == nn:
ncov = 1
size = [len(sigma)]
# find distance between coords and centroid
dist = np.linalg.norm(coords - coords.mean(axis=0), axis=1)
# pad these within a list object
coords = [coords]
max_dist = [np.ones_like(sigma)*max_dist]
sigma = [sigma]
nnz = int(1.5*(dist <= max(max_dist)).sum())
# set up matrix
mat = PETSc.Mat().create(comm)
mat.setType('aij')
mat.setSizes((nn, nn))
mat.setPreallocationNNZ((nnz,1))
mat.setOption(PETSc.Mat.Option.NEW_NONZERO_ALLOCATION_ERR, 0)
mat.setFromOptions()
mat.assemblyBegin()
colsum = np.cumsum(np.insert(size, 0, 0))
row = 0
for j in range(0, ncov):
icoord = coords[j]
imax_dist = max_dist[j]
isigma = sigma[j]
# set up KDTree and max_dist to query
tree = cKDTree(icoord)
for i in range(0, size[j]):
idx = tree.query_ball_point(icoord[i], imax_dist[i])
dist = np.linalg.norm(icoord[i] - icoord[idx], axis=1)
col = np.array(idx + colsum[j], dtype=PETSc.IntType)
val = func(isigma[idx], dist, *args, **kwargs)
mat.setValues(row, col, val)
row += 1
mat.assemblyEnd()
return mat
def create_covariance_matrix_index(sigma, coords, max_dist, index, func, *args, **kwargs):
"""
Create a covariance matrix based on distance.
Euclidean distance between a set of points is queried from a KDTree
where max_dist sets the maximum radius between points to cut-off.
Parameters
----------
sigma : values of uncertainty for each point
coords : coordindates in n-dimensions for each point
max_dist : maximum radius to search for points
index : map covariance function to regions of identical index
func : covariance function (default is Gaussian)
(pass a length parameter if using default)
args : arguments to pass to func
kwargs : keyword arguments to pass to func
Returns
-------
mat : covariance matrix
Notes
-----
Increasing max_dist increases the number of nonzeros in the
covariance matrix.
func should always receive sigma and distance as first
two inputs
"""
from scipy.spatial import cKDTree
from petsc4py import PETSc
size = len(sigma)
# find distance between coords and centroid
dist = np.linalg.norm(coords - coords.mean(axis=0), axis=1)
nnz = int(1.5*(dist <= max_dist).sum())
# set up matrix
mat = PETSc.Mat().create(comm)
mat.setType('aij')
mat.setSizes((size, size))
mat.setPreallocationNNZ((nnz,1))
mat.setOption(PETSc.Mat.Option.NEW_NONZERO_ALLOCATION_ERR, 0)
mat.setFromOptions()
mat.assemblyBegin()
lith_index = np.unique(index)
for l in lith_index:
indices = np.nonzero(index == l)[0].astype(PETSc.IntType)
icoord = coords[indices]
isigma = sigma[indices]
tree = cKDTree(icoord)
for i in indices:
idx = tree.query_ball_point(coords[i], max_dist)
dist = np.linalg.norm(coords[i] - icoord[idx], axis=1)
row = i
col = indices[idx]
val = func(isigma[idx], dist, *args, **kwargs)
mat.setValues(row, col, val)
mat.assemblyEnd()
return mat
Functions
def create_covariance_matrix(sigma, coords, max_dist, func, *args, **kwargs)
-
Create a covariance matrix based on distance. Euclidean distance between a set of points is queried from a KDTree where max_dist sets the maximum radius between points to cut-off.
Parameters
sigma : values of uncertainty for each point coords : coordindates in n-dimensions for each point max_dist : maximum radius to search for points func : covariance function (default is Gaussian) (pass a length parameter if using default) args : arguments to pass to func kwargs : keyword arguments to pass to func
Returns
mat : covariance matrix
Notes
Increasing max_dist increases the number of nonzeros in the covariance matrix.
func should always receive sigma and distance as first two inputs
Expand source code
def create_covariance_matrix(sigma, coords, max_dist, func, *args, **kwargs): """ Create a covariance matrix based on distance. Euclidean distance between a set of points is queried from a KDTree where max_dist sets the maximum radius between points to cut-off. Parameters ---------- sigma : values of uncertainty for each point coords : coordindates in n-dimensions for each point max_dist : maximum radius to search for points func : covariance function (default is Gaussian) (pass a length parameter if using default) args : arguments to pass to func kwargs : keyword arguments to pass to func Returns ------- mat : covariance matrix Notes ----- Increasing max_dist increases the number of nonzeros in the covariance matrix. func should always receive sigma and distance as first two inputs """ from scipy.spatial import cKDTree from petsc4py import PETSc ncov = len(sigma) nn = np.hstack(sigma).size if ncov < nn: # this means we have a piecewise covariance matrix if len(coords) != ncov or len(max_dist) != ncov: raise ValueError("sigma, coords, max_dist must be the same dimensions") # find the size of each list size = np.zeros(ncov, dtype=PETSc.IntType) nnz = [] for j in range(0,ncov): size[j] = len(sigma[j]) dist = np.linalg.norm(coords[j] - coords[j].mean(axis=0), axis=1) nnz_j = int(1.5*(dist <= max(max_dist[j])).sum()) nnz.append( np.ones(size[j], dtype=PETSc.IntType)*nnz_j ) nnz = np.clip(np.hstack(nnz), 1, 99999) elif ncov == nn: ncov = 1 size = [len(sigma)] # find distance between coords and centroid dist = np.linalg.norm(coords - coords.mean(axis=0), axis=1) # pad these within a list object coords = [coords] max_dist = [np.ones_like(sigma)*max_dist] sigma = [sigma] nnz = int(1.5*(dist <= max(max_dist)).sum()) # set up matrix mat = PETSc.Mat().create(comm) mat.setType('aij') mat.setSizes((nn, nn)) mat.setPreallocationNNZ((nnz,1)) mat.setOption(PETSc.Mat.Option.NEW_NONZERO_ALLOCATION_ERR, 0) mat.setFromOptions() mat.assemblyBegin() colsum = np.cumsum(np.insert(size, 0, 0)) row = 0 for j in range(0, ncov): icoord = coords[j] imax_dist = max_dist[j] isigma = sigma[j] # set up KDTree and max_dist to query tree = cKDTree(icoord) for i in range(0, size[j]): idx = tree.query_ball_point(icoord[i], imax_dist[i]) dist = np.linalg.norm(icoord[i] - icoord[idx], axis=1) col = np.array(idx + colsum[j], dtype=PETSc.IntType) val = func(isigma[idx], dist, *args, **kwargs) mat.setValues(row, col, val) row += 1 mat.assemblyEnd() return mat
def create_covariance_matrix_index(sigma, coords, max_dist, index, func, *args, **kwargs)
-
Create a covariance matrix based on distance. Euclidean distance between a set of points is queried from a KDTree where max_dist sets the maximum radius between points to cut-off.
Parameters
sigma : values of uncertainty for each point coords : coordindates in n-dimensions for each point max_dist : maximum radius to search for points index : map covariance function to regions of identical index func : covariance function (default is Gaussian) (pass a length parameter if using default) args : arguments to pass to func kwargs : keyword arguments to pass to func
Returns
mat : covariance matrix
Notes
Increasing max_dist increases the number of nonzeros in the covariance matrix.
func should always receive sigma and distance as first two inputs
Expand source code
def create_covariance_matrix_index(sigma, coords, max_dist, index, func, *args, **kwargs): """ Create a covariance matrix based on distance. Euclidean distance between a set of points is queried from a KDTree where max_dist sets the maximum radius between points to cut-off. Parameters ---------- sigma : values of uncertainty for each point coords : coordindates in n-dimensions for each point max_dist : maximum radius to search for points index : map covariance function to regions of identical index func : covariance function (default is Gaussian) (pass a length parameter if using default) args : arguments to pass to func kwargs : keyword arguments to pass to func Returns ------- mat : covariance matrix Notes ----- Increasing max_dist increases the number of nonzeros in the covariance matrix. func should always receive sigma and distance as first two inputs """ from scipy.spatial import cKDTree from petsc4py import PETSc size = len(sigma) # find distance between coords and centroid dist = np.linalg.norm(coords - coords.mean(axis=0), axis=1) nnz = int(1.5*(dist <= max_dist).sum()) # set up matrix mat = PETSc.Mat().create(comm) mat.setType('aij') mat.setSizes((size, size)) mat.setPreallocationNNZ((nnz,1)) mat.setOption(PETSc.Mat.Option.NEW_NONZERO_ALLOCATION_ERR, 0) mat.setFromOptions() mat.assemblyBegin() lith_index = np.unique(index) for l in lith_index: indices = np.nonzero(index == l)[0].astype(PETSc.IntType) icoord = coords[indices] isigma = sigma[indices] tree = cKDTree(icoord) for i in indices: idx = tree.query_ball_point(coords[i], max_dist) dist = np.linalg.norm(coords[i] - icoord[idx], axis=1) row = i col = indices[idx] val = func(isigma[idx], dist, *args, **kwargs) mat.setValues(row, col, val) mat.assemblyEnd() return mat
def gaussian(sigma, distance, length_scale)
-
Gaussian function
Expand source code
def gaussian(sigma, distance, length_scale): """ Gaussian function """ return sigma**2 * np.exp(-distance**2/(2.0*length_scale**2))