Giter Club home page Giter Club logo

rbf's Introduction

RBF

Python package containing tools for radial basis function (RBF) applications. Applications include interpolating scattered data and solving partial differential equations (PDEs) over irregular domains. Much of this package was inspired by the books "A Primer on Radial Basis Functions with Applications to the Geosciences" by Bengt Fornberg and Natasha Flyer and "Meshfree Approximation Methods with Matlab" by Gregory Fasshauer. The complete documentation for this package can be found here.

Features

  • The RBF class, which is used to evaluate RBFs and their exact derivatives
  • The RBFInterpolant class, which is used to interpolate scattered and potentially noisy N-dimensional data. One can also evaluate the exact derivatives of the interpolant
  • The weight_matrix function, which generates radial basis function finite difference (RBF-FD) weights. This is used for solving large scale PDEs over irregular domains
  • Node generation functions, such as min_energy_nodes and poisson_disc_nodes, which are used for solving PDEs with the spectral RBF method or the RBF-FD method
  • Computational geometry functions (e.g. point in polygon testing) for two and three spatial dimensions
  • The GaussianProcess class, which is used for Gaussian process regression (GPR). GPR is similar to RBF interpolation, except it has a Bayesian statistical foundation

Installation

This package is available on PyPI and can be installed with

$ pip install treverhines-rbf

To install the latest version, clone this project and install it from the top-level directory with

$ pip install . -r requirements.txt

Test that the installation works by going into the test directory and running

$ python -m unittest discover

Demonstration

Interpolating scattered data

'''
Interpolating scattered observations of Franke's test function with RBFs.
'''
import numpy as np
from rbf.interpolate import RBFInterpolant
import matplotlib.pyplot as plt
np.random.seed(1)

def frankes_test_function(x):
    '''A commonly used test function for interpolation'''
    x1, x2 = x[:, 0], x[:, 1]
    term1 = 0.75 * np.exp(-(9*x1-2)**2/4 - (9*x2-2)**2/4)
    term2 = 0.75 * np.exp(-(9*x1+1)**2/49 - (9*x2+1)/10)
    term3 = 0.5 * np.exp(-(9*x1-7)**2/4 - (9*x2-3)**2/4)
    term4 = -0.2 * np.exp(-(9*x1-4)**2 - (9*x2-7)**2)
    y = term1 + term2 + term3 + term4
    return y

# observation points
x_obs = np.random.random((100, 2))
# values at the observation points
u_obs = frankes_test_function(x_obs)
# evaluation points
x_itp = np.mgrid[0:1:200j, 0:1:200j].reshape(2, -1).T

interp = RBFInterpolant(x_obs, u_obs)
# interpolated values at the evaluation points
u_itp = interp(x_itp)

# plot the results
plt.tripcolor(
    x_itp[:, 0], x_itp[:, 1], u_itp, cmap='viridis', vmin=0.0, vmax=1.2
    )
plt.scatter(
    x_obs[:, 0], x_obs[:, 1], s=100, c=u_obs, cmap='viridis', vmin=0.0,
    vmax=1.2, edgecolor='k'
    )
plt.xlim(0, 1)
plt.ylim(0, 1)
plt.colorbar()
plt.tight_layout()
plt.show()
docs/figures/interpolate.f.png

Solving PDEs

There are two methods for solving PDEs with RBFs: the spectral method and the RBF-FD method. The spectral method has been touted as having remarkable accuracy; however it is only applicable for small scale problems and requires a good choice for a shape parameter. The RBF-FD method is appealing because it can be used for large scale problems, there is no need to tune a shape parameter (assuming you use polyharmonic splines to generate the weights), and higher order accuracy can be attained by simply increasing the stencil size or increasing the order of the polynomial used to generate the weights. In short, the RBF-FD method should always be preferred over the spectral RBF method. An example of the two methods is provided below.

'''
In this example we solve the Poisson equation over an L-shaped domain with
fixed boundary conditions. We use the multiquadric RBF (`mq`)
'''
import numpy as np
from rbf.basis import mq
from rbf.pde.geometry import contains
from rbf.pde.nodes import poisson_disc_nodes
import matplotlib.pyplot as plt

# Define the problem domain with line segments.
vert = np.array([[0.0, 0.0], [2.0, 0.0], [2.0, 1.0],
                 [1.0, 1.0], [1.0, 2.0], [0.0, 2.0]])
smp = np.array([[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 0]])

spacing = 0.07 # approximate spacing between nodes

eps = 0.3/spacing  # shape parameter

# generate the nodes. `nodes` is a (N, 2) float array, `groups` is a dict
# identifying which group each node is in
nodes, groups, _ = poisson_disc_nodes(spacing, (vert, smp))
N = nodes.shape[0]

# create "left hand side" matrix
A = np.empty((N, N))
A[groups['interior']] = mq(nodes[groups['interior']], nodes, eps=eps, diff=[2, 0])
A[groups['interior']] += mq(nodes[groups['interior']], nodes, eps=eps, diff=[0, 2])
A[groups['boundary:all']] = mq(nodes[groups['boundary:all']], nodes, eps=eps)

# create "right hand side" vector
d = np.empty(N)
d[groups['interior']] = -1.0 # forcing term
d[groups['boundary:all']] = 0.0 # boundary condition

# Solve for the RBF coefficients
coeff = np.linalg.solve(A, d)

# interpolate the solution on a grid
xg, yg = np.meshgrid(np.linspace(0.0, 2.02, 100),
                     np.linspace(0.0, 2.02, 100))
points = np.array([xg.flatten(), yg.flatten()]).T
u = mq(points, nodes, eps=eps).dot(coeff)
# mask points outside of the domain
u[~contains(points, vert, smp)] = np.nan
# fold the solution into a grid
ug = u.reshape((100, 100))
# make a contour plot of the solution
fig, ax = plt.subplots()
p = ax.contourf(xg, yg, ug, np.linspace(0.0, 0.16, 9), cmap='viridis')
ax.plot(nodes[:, 0], nodes[:, 1], 'ko', markersize=4)
for s in smp:
  ax.plot(vert[s, 0], vert[s, 1], 'k-', lw=2)

ax.set_aspect('equal')
ax.set_xlim(-0.05, 2.05)
ax.set_ylim(-0.05, 2.05)
fig.colorbar(p, ax=ax)
fig.tight_layout()
plt.show()
docs/figures/basis.a.png
'''
In this example we solve the Poisson equation over an L-shaped domain with
fixed boundary conditions. We use the RBF-FD method. The RBF-FD method is
preferable over the spectral RBF method because it is scalable and does not
require the user to specify a shape parameter (assuming that we use odd order
polyharmonic splines to generate the weights).
'''
import numpy as np
from scipy.sparse import coo_matrix
from scipy.sparse.linalg import spsolve
import matplotlib.pyplot as plt

from rbf.sputils import expand_rows
from rbf.pde.fd import weight_matrix
from rbf.pde.geometry import contains
from rbf.pde.nodes import poisson_disc_nodes

# Define the problem domain with line segments.
vert = np.array([[0.0, 0.0], [2.0, 0.0], [2.0, 1.0],
                 [1.0, 1.0], [1.0, 2.0], [0.0, 2.0]])
smp = np.array([[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 0]])

spacing = 0.07 # approximate spacing between nodes

n = 25 # stencil size. Increase this will generally improve accuracy

phi = 'phs3' # radial basis function used to compute the weights. Odd
             # order polyharmonic splines (e.g., phs3) have always performed
             # well for me and they do not require the user to tune a shape
             # parameter. Use higher order polyharmonic splines for higher
             # order PDEs.

order = 2 # Order of the added polynomials. This should be at least as
          # large as the order of the PDE being solved (2 in this case). Larger
          # values may improve accuracy

# generate nodes
nodes, groups, _ = poisson_disc_nodes(spacing, (vert, smp))
N = nodes.shape[0]

# create the components for the "left hand side" matrix.
A_interior = weight_matrix(
    x=nodes[groups['interior']],
    p=nodes,
    n=n,
    diffs=[[2, 0], [0, 2]],
    phi=phi,
    order=order)
A_boundary = weight_matrix(
    x=nodes[groups['boundary:all']],
    p=nodes,
    n=1,
    diffs=[0, 0])
# Expand and add the components together
A  = expand_rows(A_interior, groups['interior'], N)
A += expand_rows(A_boundary, groups['boundary:all'], N)

# create "right hand side" vector
d = np.zeros((N,))
d[groups['interior']] = -1.0
d[groups['boundary:all']] = 0.0

# find the solution at the nodes
u_soln = spsolve(A, d)

# Create a grid for interpolating the solution
xg, yg = np.meshgrid(np.linspace(0.0, 2.02, 100), np.linspace(0.0, 2.02, 100))
points = np.array([xg.flatten(), yg.flatten()]).T

# We can use any method of scattered interpolation (e.g.,
# scipy.interpolate.LinearNDInterpolator). Here we repurpose the RBF-FD method
# to do the interpolation with a high order of accuracy
I = weight_matrix(
    x=points,
    p=nodes,
    n=n,
    diffs=[0, 0],
    phi=phi,
    order=order)
u_itp = I.dot(u_soln)

# mask points outside of the domain
u_itp[~contains(points, vert, smp)] = np.nan
ug = u_itp.reshape((100, 100)) # fold back into a grid

# make a contour plot of the solution
fig, ax = plt.subplots()
p = ax.contourf(xg, yg, ug, np.linspace(-1e-6, 0.16, 9), cmap='viridis')
ax.plot(nodes[:, 0], nodes[:, 1], 'ko', markersize=4)
for s in smp:
  ax.plot(vert[s, 0], vert[s, 1], 'k-', lw=2)

ax.set_aspect('equal')
ax.set_xlim(-0.05, 2.05)
ax.set_ylim(-0.05, 2.05)
fig.colorbar(p, ax=ax)
fig.tight_layout()
plt.show()
docs/figures/fd.i.png

rbf's People

Contributors

cossatot avatar dougmvieira avatar physics-enthusiast avatar treverhines avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rbf's Issues

Vertices defining simplices are not preserved?

I'm trying to use your package to solve a heat transfer problem on an irregular domain using radial basis functions. When I use min_energy_nodes, the vertices at the corners of the domain are not part of the set of nodes returned by min_energy_nodes. Is there an easy way to force this, so that the corners of the domain do not get truncated?

Trying to understand how to apply Method Of Lines with RBF-FD

Hello,

I read the example about conductivity and there are some things that I do not get :

  1. Why do ghost nodes boundary operator B_free write neuman conditions at ghost nodes position whilst free nodes express same operator as Dirichlet and interior on B_temp i. e. identity for their respectives coordinates.
  2. Why is differentiation matrix A applied on interior AND null flux edges ?
  3. Why does state derivative write A @ (Bsolver.solve(z) ?
    A @ (Bsolver.solve(z) being equivalent to A @ inv(B) @ z meaning :

$$ \frac{d \mathbf{z}}{dt} = \mathbf{A} \mathbf{B}^{-1}\mathbf {z} $$

I clearly do not get how the time derivative is build with the method of lines. Could you help me to understand ?

Roman

Here is Trever Hines example attached :

'''
This script demonstrates using RBF-FD to solve the heat equation with spatially
variable conductivity, k(x, y). Namely,

    u_t = k_x*u_x + k*u_xx + k_y*u_y + k*u_yy

'''
import logging

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
from scipy.sparse.linalg import splu
from scipy.integrate import solve_ivp

from rbf.pde.nodes import poisson_disc_nodes
from rbf.pde.fd import weight_matrix
from rbf.pde.geometry import contains
from rbf.sputils import expand_rows, expand_cols

logging.basicConfig(level=logging.DEBUG)

node_spacing = 0.1
radial_basis_function = 'phs3' # 3rd order polyharmonic spline
polynomial_order = 2
stencil_size = 30
time_evaluations = np.linspace(0, 1, 41)

vertices = np.array(
    [[-2.    ,  2.    ], [ 2.    ,  2.    ], [ 2.    , -2.    ],
     [-2.    , -2.    ], [ 1.    ,  0.    ], [ 0.9239,  0.3827],
     [ 0.7071,  0.7071], [ 0.3827,  0.9239], [ 0.    ,  1.    ],
     [-0.3827,  0.9239], [-0.7071,  0.7071], [-0.9239,  0.3827],
     [-1.    ,  0.    ], [-0.9239, -0.3827], [-0.7071, -0.7071],
     [-0.3827, -0.9239], [-0.    , -1.    ], [ 0.3827, -0.9239],
     [ 0.7071, -0.7071], [ 0.9239, -0.3827]]
    )

simplices = np.array(
    [[0 , 1 ], [1 , 2 ], [2 , 3 ], [3 , 0 ], [4 , 5 ], [5 , 6 ], [6 , 7 ],
     [7 , 8 ], [8 , 9 ], [9 , 10], [10, 11], [11, 12], [12, 13], [13, 14],
     [14, 15], [15, 16], [16, 17], [17, 18], [18, 19], [19,  4]]
    )

boundary_groups = {
    'fixed': [1, 3],
    'free': [0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
    }

def conductivity(x):
    out = 1 + 3*(1 / (1 + np.exp(-5*x[:, 1])))
    return out

def conductivity_xdiff(x):
    # finite difference x derivative of conductivity
    delta = 1e-3
    out = (conductivity(x + [delta, 0.0]) - conductivity(x))/delta
    return out

def conductivity_ydiff(x):
    # finite difference y derivative of conductivity
    delta = 1e-3
    out = (conductivity(x + [0.0, delta]) - conductivity(x))/delta
    return out

# Generate the nodes. `groups` identifies which group each node belongs to.
# `normals` contains the normal vectors corresponding to each node (nan if the
# node is not on a boundary). We are giving the free boundary nodes ghost
# nodes to improve the accuracy of the free boundary constraint.
nodes, grp, normals = poisson_disc_nodes(
    node_spacing,
    (vertices, simplices),
    boundary_groups=boundary_groups,
    boundary_groups_with_ghosts=['free']
    )

# We will solve the heat equation by numerically integrating the state vector
# `z`. The state vector consists of:
#   - The temperature of the interior nodes at z[grp['interior']]
#   - The temperature of the fixed boundary at z[grp['boundary:fixed']]
#   - The temperature of the free boundary at z[grp['boundary:free']]
#   - The boundary condition at the free boundary at z[grp['ghosts:free']]
#
z_init = np.zeros(nodes.shape[0])
z_init[grp['boundary:fixed']] = nodes[grp['boundary:fixed'], 0]

# Create a matrix that maps the temperature at `nodes` to the state vector.
# Then create a solver for it, so we can map the state vector to the
# temperature at all nodes.

# `idx` are the indices for all nodes except the ghost nodes. The mapping to
# the state vector is just an identity mapping so we only need a stencil size
# of 1.
idx = np.hstack((grp['interior'], grp['boundary:fixed'], grp['boundary:free']))
B_temp = weight_matrix(
    x=nodes[idx],
    p=nodes,
    n=1,
    diffs=[0, 0]
    )
B_free = weight_matrix(
    x=nodes[grp['boundary:free']],
    p=nodes,
    n=stencil_size,
    diffs=[[1, 0], [0, 1]],
    coeffs=[
        normals[grp['boundary:free'], 0],
        normals[grp['boundary:free'], 1]
        ],
    phi=radial_basis_function,
    order=polynomial_order
    )

B = expand_rows(B_temp, idx, nodes.shape[0])
B += expand_rows(B_free, grp['ghosts:free'], nodes.shape[0])
B = B.tocsc()
Bsolver = splu(B)

# construct a matrix that maps the temperature at `nodes` to the time
# derivative of the state vector

# `idx` are the indices of the state vector with a non-zero time derivative
# (i.e., the elements of the state vector that are not enforcing the boundary
# conditions).
idx = np.hstack((grp['interior'], grp['boundary:free']))
A = weight_matrix(
    x=nodes[idx],
    p=nodes,
    n=stencil_size,
    diffs=[[1, 0], [2, 0], [0, 1], [0, 2]],
    coeffs=[
        conductivity_xdiff(nodes[idx]),
        conductivity(nodes[idx]),
        conductivity_ydiff(nodes[idx]),
        conductivity(nodes[idx])
        ],
    phi=radial_basis_function,
    order=polynomial_order
    )
A = expand_rows(A, idx, nodes.shape[0])
A = A.tocsc()

def state_derivative(t, z):
    return A.dot(Bsolver.solve(z))

soln = solve_ivp(
    fun=state_derivative,
    t_span=[time_evaluations[0], time_evaluations[-1]],
    y0=z_init,
    method='RK45',
    t_eval=time_evaluations
    )

## PLOTTING
# create the interpolation points
xy_grid = np.mgrid[-2.01:2.01:200j, -2.01:2.01:200j]
xy = xy_grid.reshape(2, -1).T

# create an interpolation matrix that maps the state vector to the temperature
# at `xy`. `idx` consists of indices of the state vector that are temperatures.
idx = np.hstack((grp['interior'], grp['boundary:fixed'], grp['boundary:free']))
I = weight_matrix(
    x=xy,
    p=nodes[idx],
    n=stencil_size,
    diffs=[0, 0],
    phi=radial_basis_function,
    order=polynomial_order
    )
I = expand_cols(I, idx, nodes.shape[0])

# create a mask for points in `xy` that are outside of the domain
is_outside = ~contains(xy, vertices, simplices)

fig1, ax1  = plt.subplots()
k = conductivity(xy)
k[is_outside] = np.nan
k = k.reshape(200, 200)
p = ax1.contourf(*xy_grid, k, np.linspace(1, 4, 11), cmap='viridis')

for smp in simplices:
    ax1.plot(vertices[smp, 0], vertices[smp, 1], 'k-', zorder=1)

for i, (k, v) in enumerate(grp.items()):
    ax1.scatter(nodes[v, 0], nodes[v, 1], s=10, c='C%d' % i, label=k, zorder=2)

ax1.set_aspect('equal')
ax1.set_xlim(-2.2, 2.2)
ax1.set_ylim(-2.2, 2.2)
ax1.grid(ls=':', color='k')
ax1.legend()
cbar = fig1.colorbar(p)
cbar.set_label('heat conductivity')
fig1.tight_layout()
plt.savefig('../figures/fd.n.1.png')

fig2 = plt.figure()
# create the update function for the animation. this plots the solution at time
# `time[index]`
def update(index):
    fig2.clear()
    ax2 = fig2.add_subplot(111)

    z = soln.y[:, index]
    temp = I.dot(z)
    temp[is_outside] = np.nan
    temp = temp.reshape((200, 200))

    for s in simplices:
        ax2.plot(vertices[s, 0], vertices[s, 1], 'k-')

    p = ax2.contourf(
        *xy_grid,
        temp,
        np.linspace(-2.0, 2.0, 10),
        cmap='viridis',
        extend='both'
        )

    ax2.scatter(nodes[:, 0], nodes[:, 1], c='k', s=2)
    ax2.set_title('temperature at time: %.2f' % time_evaluations[index])

    ax2.set_xlim(-2.1, 2.1)
    ax2.set_ylim(-2.1, 2.1)
    ax2.grid(ls=':', color='k')
    ax2.set_aspect('equal')
    fig2.colorbar(p)
    fig2.tight_layout()

ani = FuncAnimation(
    fig=fig2,
    func=update,
    frames=range(len(time_evaluations)),
    repeat=True,
    blit=False
    )

ani.save('../figures/fd.n.2.gif', writer='imagemagick', fps=3)
plt.show()

Cannot import from extension modules

I installed RBF. However, I cannot import anything from the extension modules. Interestingly, if I work from the build directory (for me, it is /RBF/build/lib.linux-x86_64-3.7), there is no issue. The problem arises when Python imports from the installed .egg file. For instance:

>>> from rbf.linalg import *
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/zoltan/anaconda3/lib/python3.7/site-packages/RBF-2021.5.15+7.g50e4b5d-py3.7-linux-x86_64.egg/rbf/linalg.py", line 14, in <module>
ImportError: cannot import name 'row_norms' from 'rbf.sputils' (/home/zoltan/.cache/Python-Eggs/RBF-2021.5.15+7.g50e4b5d-py3.7-linux-x86_64.egg-tmp/rbf/sputils.cpython-37m-x86_64-linux-gnu.so)

Do you have an idea why it happens?

LOO cross validation implementation

The documentation talks about automatic estimation of the smoothing parameter sigma and/or kernel scale parameter epsilon for the RBFInterpolatant, using leave-one-out cross validation (LOOCV).

After reading through the implementation, it looks to me like it is performing just a single pass optimization over the whole dataset (instead of looping over cross-validation subsamples).

Could you point me to where the cross validation is happening?

Most effective way to scale up to HPC on a large mesh problem

Hello,
I'm trying to interpolate a noisy dataset on a very large mesh. I have the chance to submit this task to an HPC machine with a significant amount of computational resources (up to a few hundreds of cores without too much hassle, even more if really needed, terabytes of RAM etc.), but to do so I need at least some estimate of the resources needed. Unfortunately, my laptop is barely capable of running my code to verify on a reduced dimensionality problem, so I'm not confident that testing different strategies locally is an effective benchmarking strategy.

To give some context, the complete mesh I want to populate is of 768x1024x20x768x1024 (10^13 points), let's call these dimension respectively u,v,wave,x,y. On my laptop, I run the interpolant in loops, spanning over u,v,wave, creating meshes with fixed U,V,LAMBDA such that

for U in u:
    for V in V:
        for WAVE in wave:
            mesh = make_mesh(U,V,WAVE)
            result = kernel_interpolant_5d(mesh)
            result = result.reshape((768,1024))
            complete_dataset[U,V,LAMBDA,:,:] = result

The kernel interpolant I'm using has sigma!=0, neighbors=50-80, phi = "wen12" (I need compact support, because the dynamic I'm interested is extended to really small values and the ripples extending over the whole mesh are messing with my results)
To effectively scale up, I don't know which is the best option among the following:

  1. Do not parallelize the code and scale up the mesh directly
  2. Embarassingly parallelizing the loop, spawning jobs and keep a reduced mesh, eventually doing some tests to see how many cores per job are effective.

Can someone point me in the right direction? I have limited time to experiment on this and almost no HPC experience.

Looking for a proper way to provide faces from extruded 2D polygons

Hello again,
I have been using your python library for a while and I still face some difficulties about the geometry generation. To give context about my difficulties, I try to generate a box with some obstacles on the bottom coming from a shapefile. This file format lists obstacles 2D footprints with their height. I know how to give polygon coordinates as vertices but I need to provide to RBF-library some information of connectivity, in 3D it consists to give a list of triangles with indices corresponding to the vertices we want to connect. For the moment I manage to get, faces of my extruded footprints with the use of convex hull python function but this modify the form of my obstacles. Is there a way to extract faces of an extruded 2D obstacle without modifying its form?
For example, given polygon coordinates and height information, how can I extract properly the faces of the 3D extruded Polygon in the figure without modifying its form?

image

Sorry for bothering you and thank you a lot for your help.

Roman

Removal of lambdify

Hello, cool package you have here! The PDE weight matrix functionality in particular has been rather useful. Just wondering, was there any reason why the set_symbolic_to_numeric_method toggle to use lambdify needed to be removed entirely? Admittedly, usecases involving calculations >15 dimensions that don't cause most computers to burst into flames through their sheer memory requirements alone seem quite scarce, but at least having the option to do so was nice even if it came at a performance cost. This is with reference to commit 3cad702.

Citing this Repository in my work!

Could somebody please tell me how to cite this repository? I am a PhD student and have used this repository in my work. I have found that GitHub has added support for direct citations but couldn't figure out how to do it for this repository.

Thanks

Extension for vector-valued observations

Since I am interested in using this library for morphing, I need to deal with vector-valued observations. One way of doing it is to perform the RBF interpolation for each component of the vector data. Another, possibly more efficient, strategy is to solve the problem at once by replacing the right-hand side vector with a matrix. Currently, rbf.utils.assert_shape stops me from doing it:

ValueError: d is 2 dimensional but it should have 1 dimensions

Do you see any technical difficulty of implementing this feature? I don't know about your solvers, but numpy.linalg.solve can handle matrix right-hand sides.

Periodic approximations

Hello,

for some numerical benchmarks it would be useful to have a version of the weights and weight_matrix functions that would take into account the periodicity of the domain. Given a point where we seek an approximation and a set of centers (that have already been selected taking periodicity into account) it is only necessary to add a correction during the calculation of the distance matrix (for both the RBF part and shifted monomials). For example, if the domain is periodic in x-direction:

if (periodic_x):
  dx = x(j) - x(i)
  if (dx >   x_size * 0.5): dx = dx - x_size
  if (dx <= -x_size * 0.5): dx = dx + x_size
end if

The dx (and dy) are then used to calculate the radial distance that goes into the RBF. I had a look at the internals of the library and identified line 317 in pde/basis.py as the place where this is performed on symbolic level. Do you have any suggestion how to go about this? Is the easiest way just to create 9 copies of the nodes (e.g. for bi-periodic in 2d), and then loop through the nodes calling the weights function, and place the weights into a sparse matrix?

I also have a question whether there is any reason when you fill the RBF-FD matrix, you do not shift the monomial part by the centers of the approximation?

Thank you for sharing your work.

Ivan

Serialization of RBFInterpolant objects

Hello,

It is sometimes useful to serialize RBFInterpolant objects and send them across the network or save and restore them from file. However, the usual pickle machinery complains that it cannot handle the '_basis' field of RBFInterpolant because it is a function. One solution is to allow passing of basis function coefficients to the RBFInterpolant constructor, so that interpolant objects can be quickly reconstituted after serializing their _y and _coeff fields. I would appreciate any solution to this problem.

Release pip-installable version

Thanks for this package! I am wondering if you'd be willing to release it to pip so it can be installed via pip install rbf or similar? I'd be happy to prepare a PR with the necessary setup.

Related #14

Can't specify node snapping distance from min_energy_nodes

In rbf.nodes.min_energy_nodes, the keyword delta is passed to rbf.nodes._disperse_within_boundary; it is also the name of the snapping distance parameter in rbf.nodes._snap_to_boundary even though the parameters aren't the same thing--as a consequence, a default value of 0.5 is hardcoded as the delta for the snapping function. However, I've needed to modify this parameter from a script so hardcoding it doesn't work for me.

I'm jointly submitting a pull request that uses a keyword snap_deltain min_energy_nodes to allow the user to specify this value and avoid a name collision with the delta function used to disperse the nodes.

On the possibility of extracting a mesh from min_energy_nodes

Hello,

I recently asked myself, for plot utilites and node refinement in a 3D domain if it was possible to extract a unstructured triangular mesh from the nodes and normals returned by the function min_energy_nodes. As we extract the normals I guess triangulation is involved in the process. Is there a way to recover a whole mesh by applying min_energy_nodes ?

Best regards,

Roman

Using this RBF package for complex numbers interpolation

Hello Trever,

First of all, thanks a lot for making this package open. It has been extremely helpful in my research work. I have a question regarding the rbf interpolation for complex numbers. As far as I understand, this package can do interpolation for real numbers. When I tried to do it for complex numbers, it simply ignored the imaginary part and only considered the real part of the complex number for generating interpolants. Is it possible to modify the code so that it also interpolates the complex numbers?

Thanks

Pressure Poisson equation giving wrong results

Hello, I'm trying to recover the pressure field from a known fluid velocity field using the pressure Poisson equation.
I'm able to compute spatial derivatives of the velocity vector components. I know these are correct: I have ground truth derivatives.

I have assembled the right hand side of the pressure Poisson equation as:

bx = - rho * (u_t + rho * (u * u_x + v * u_y + w * u_z)) + mu * (u_xx + u_yy + u_zz)
by = - rho * (v_t + rho * (u * v_x + v * v_y + w * v_z)) + mu * (v_xx + v_yy + v_zz)
bz = - rho * (w_t + rho * (u * w_x + v * w_y + w * w_z)) + mu * (w_xx + w_yy + w_zz)
rhs = Wx.dot(bx) + Wy.dot(by) + Wz.dot(bz)

with subscripts indicating derivatives, rho and mu are fluid density and viscosity.
Then, I assembled the RBF weight matrix as: Wppe = weight_matrix(nodes[interiorIDs], nodes, n=80, [[2,0,0], [0,2,0], [0,0,2]], phi='phs5', order=5), and applied boundary conditions to Wppe and rhs.
However, when I solve the linear system, I obtain wrong pressure fields, both in patterns and values (15 orders of magnitude higher!).

I've tried lots of combinations for assembling the rhs and the coefficient matrix with no success.

Is there something wrong in the way I'm using the weight_matrix function? Or could the problem be related to my rhs?

Any advice or help would be greatly appreciated.
Thanks!

Having trouble to understand if RBF-FD is able to deal with internal boundaries

Hello,

I do not know if it is the best place to ask a question but I try. I have carefully read the docs but I still do not know if your library able to deal with internal constraints ? Such as in this example from Medusa, a C++ RBF-FD library,

image
image

By the way, is it possible to set a constraint to the inner boundary which differs from the outer one with the RBF library ?

Congratulations for your work,

Roman

Reuse interpolator for repeated evaluation of different variables

Is there a way to reuse the rbf interpolator (or parts of it) to speed up repeated evaluation of different variables between the same two meshes/point distributions? I want to interpolate results from a numerical simulation between to different grids. The two grids are always the same, but since there are several variables, currently I have to run the whole interpolation in a loop:

for key in oldMesh.keys():
    interpolator = RBFInterpolant(
        np.array([oldMesh["X"], oldMesh["Y"]]).T, 
        oldMesh[key], 
        phi="phs3", 
        order=1, 
        sigma=0.0001,
    ) 
    interpolationPositions = np.reshape(
        (xx,yy), (2, nInterpolationPoints*nInterpolationPoints)
    ).T
    fieldInterpolated = interpolator(interpolationPositions)
    newMesh[key] = fieldInterpolated.flatten()

Is there a way to speed this up?

Trying to understand _disperse_step

Hello Trever,

In rbf/pde
/nodes.py at _disperse_step function you compute a proportionality constant based on electrorepulsion law with the support of $\rho$ density function. You wrote :

 all_nodes = np.vstack((nodes, fixed_nodes))
    # find index and distance to nearest nodes
    dist, idx = KDTree(all_nodes).query(nodes, neighbors + 1)
    # dont consider a node to be one of its own nearest neighbors
    dist, idx = dist[:, 1:], idx[:, 1:]
    # compute the force proportionality constant between each node
    # based on their charges
    c = 1.0/(rho(all_nodes)[idx, None]*rho(nodes)[:, None, None])
    # calculate forces on each node resulting from the neighboring nodes. This
    # will result in a division by zero warning if there are duplicate nodes.
    # Do not suppress the warning because it is a real problem.
    forces = c*(nodes[:, None, :] - all_nodes[idx, :])/dist[:, :, None]**3
    # sum up all the forces for each node to get the direction that the nodes
    # should move.
    direction = np.sum(forces, axis=1)
  • $\mathbf{X}$ the set of all nodes of dimension $(N,d)$,
  • $\mathbf{S}$ the set neighbour nodes dimension $(m,d)$,
    Basically if no fix nodes are specified you have :
    $\mathbf{X}$ the set of all nodes of dimension $(N,d)$,
  • $\mathbf{S}$ the set neighbour nodes dimension $(m,d)$,
    Basically if no fix nodes are specified you have :

$$ c(\mathbf{X, S}) = 1 / (\rho(\mathbf{X}) \rho(\mathbf{S})) $$

And compute forces with,

$$ \mathbf{F}_{\mathbf{X}on \mathbf{S}} = \frac{1}{\rho(\mathbf{X}) \rho(\mathbf{S})} \frac{\mathbf{S} - \mathbf{X}}{| \mathbf{S} - \mathbf{X}|^3} $$

Where for Cloumb's law force exerced by charged by a particule 1 on particule 2 is,

$$ \vec{F}_{1 / 2}= {q_1 q_2} \frac{\vec{r}_2-\vec{r}_1}{\left|\vec{r}_2-\vec{r}_1\right|^3} $$

Does it mean that you assume that node density is $\rho$ is equivalent to $1/q$ in term of charge density ?

Best regards,
Roman

Problem while installing

Hi Trever,

I am having a problem while executing the "python setup.py install" command line. It ends up with a fatal error as follow:
"/usr/bin/clang -fno-strict-aliasing -Wsign-compare -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -arch i386 -arch x86_64 -g -I/Library/Frameworks/Python.framework/Versions/3.6/include/python3.6m -c rbf/halton.c -o build/temp.macosx-10.6-intel-3.6/rbf/halton.o
rbf/halton.c:579:10: fatal error: 'numpy/arrayobject.h' file not found
#include "numpy/arrayobject.h"
^
1 error generated.
error: command '/usr/bin/clang' failed with exit status 1"

I updated the numpy, scipy, sympy, cython, and networkx python packages but it's still throwing me this error while trying to install the RBF package.

Do you know how I can fix this?

Regards,
Lucas

conda installation not working

Hi Trever,
Thank you for the great job. I have been using your library for a while and find it very useful.

I want to include your library as part of the conda env requirements for a library I am working on, but I can't manage to install rbf with conda. In the documentation you mentioned:

conda install rbf -c treverhines -c conda-forge

But I get the following error:

`PackagesNotFoundError: The following packages are not available from current channels:

  • rbf

Current channels:

Thank you again,
JP

Some windows installations do not have a c compiler, please allow for python only execution.

RBF requires a c compiler to be present during installation and also during routine execution after installation (required for sympy symbolic to executable code). Building a binary wheel allowed me to install RBF on another computer, but then during execution it still required a compiler to build code.

Please provide the option to use Python only for users without c compilers (e.g., on Windows). Something like

if ccompiler:
ufuncify(x_sym+c_sym+(_EPS,), expr,backend='numpy')
else:
sympy.lambdify(x_sym+c_sym+(_EPS,), expr, modules=['numpy'])

thanks and keep up the good work!

Add sequence start argument to min_energy_nodes

Hello,

Sometimes it is useful to provide a different starting point to the Halton sequence used in min_energy_nodes. The attached patch adds option start to min_energy_nodes and rejection_sampling, when then is passed to the underlying HaltonSequence object. Thanks for the consideration.

diff --git a/rbf/pde/nodes.py b/rbf/pde/nodes.py
index 72816e3..21b212e 100644
--- a/rbf/pde/nodes.py
+++ b/rbf/pde/nodes.py
@@ -428,7 +428,7 @@ def prepare_nodes(nodes, domain,
   return nodes, groups, normals
 
   
-def min_energy_nodes(n, domain, rho=None, build_rtree=False, 
+def min_energy_nodes(n, domain, rho=None, build_rtree=False, start=0,
                      **kwargs):
   '''
   Generates nodes within a two or three dimensional. This first
@@ -536,7 +536,7 @@ def min_energy_nodes(n, domain, rho=None, build_rtree=False,
     def rho(x): 
         return np.ones(x.shape[0])
 
-  nodes = rejection_sampling(n, rho, domain)
+  nodes = rejection_sampling(n, rho, domain, start=start)
   out = prepare_nodes(nodes, domain, rho=rho, **kwargs)
   return out                      
 
diff --git a/rbf/pde/sampling.pyx b/rbf/pde/sampling.pyx
index 82b1a07..f12900e 100644
--- a/rbf/pde/sampling.pyx
+++ b/rbf/pde/sampling.pyx
@@ -32,7 +32,7 @@ cdef double distance(list a, list b):
     return sqrt(out)        
             
 
-def rejection_sampling(size, rho, domain, max_sample_size=1000000):
+def rejection_sampling(size, rho, domain, start=0, max_sample_size=1000000):
     '''
     Returns points within the boundaries defined by `vert` and `smp`
     and with density `rho`. The nodes are generated by rejection
@@ -71,7 +71,7 @@ def rejection_sampling(size, rho, domain, max_sample_size=1000000):
     # and 1
     rng = HaltonSequence(1, prime_index=0)
     # form a Halton sequence to generate the test points
-    pnt_rng = HaltonSequence(domain.dim, prime_index=1)
+    pnt_rng = HaltonSequence(domain.dim, prime_index=1, start=start)
     # initiate array of points
     points = np.zeros((0, domain.dim), dtype=float)
     # node counter

Cannot Install on MacOS?

When attempting to install on macOS (m1 processor), there is an error building the wheels. I am using pip install treverhines-rbf, and the error I am getting is "ERROR: ERROR: Failed to build installable wheels for some pyproject.toml based projects (treverhines-rbf)". I have tried both pip install and trying to download it from the git clone directory in my project folder, and I get the same error for both. Anybody know a way to download on macOS? Thanks.

Reduce CPU usage by limiting number of threads

Hey,
as I'd like to to use this package operationally I need some way to limit the maximum number of threads used when interpolating in order to prevent the server to fill up CPU usage with the interpolation.
For scipy I use something like

os.environ["OPENBLAS_NUM_THREADS"] = "4"

but this package uses cython and probably the number of threads is defined there?
Thanks

no module named "rbf.poly"

hello,
when i try to run one of your examples the python sends this error:

Reloaded modules: rbf._version, rbf
Traceback (most recent call last):

File "C:\Users\frant\Desktop\RSM_v5\untitled2.py", line 9, in
from rbf.basis import mq

File "C:\Users\frant\rbf\basis.py", line 60, in
from rbf.poly import monomial_powers

ModuleNotFoundError: No module named 'rbf.poly'

can you please help me?

Are there ways to deal with 1D case ?

Hello,

Is a way to proceed an RBF-FD method with this library on a 1D domain such as a line of points generated by an Halton set where we could for example consider a stationnary convection diffusion equation such as,

$$ \begin{align} U \cdot \frac{dc}{dx} - K \frac{d^2c}{dx^2} &= \delta(x-0.5) &\quad x \in \Omega = ]0,1[\\ c &= 0 &\quad x = 0, \\ &\frac{dc}{dx} = 1 &\quad x = 1 \end{align} $$

image

Do you have an hint ? I read that min_energy_nodes and poisson_disc_nodes are adapted to 2D and 3D domain. But how could 1D nodes and normals be generated ?

Thank you again providing this powerfull librairy,

Roman

How to solve a 2D problem with an obstacle with some interior nodes inside of it

Hello again,
I meet difficulties to procceed diffusion on a domain occupied by a sort of court-yard, with the model :

\begin{align}
- v\Delta u &= s\delta(x-x_S), \quad &x \in \Omega \\
\nabla u.n &= 0 \quad &x \in \Gamma_N \\
u(x) &= 0, \quad &x \in \Gamma_D
\end{align}

image

on the domain :

image

The source is located at the outside of the courtyard. A neuman zero-flux condition is set on the edges of the obstacle. However, the solution inside the courtyard is not equal to zero which is not physical as visible below.

image

Do you know how I could avoid this issue ?

Here is my code :

# -*- coding: utf-8 -*-
"""
Created on 12 2021

@author: Roman Lopez-Ferber
"""
import numpy as np

from rbf.pde.geometry import simplex_outward_normals
from rbf.pde.fd import weight_matrix, weights
from rbf.sputils import expand_rows
from scipy.spatial import cKDTree
import time

import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import scipy.sparse as sp

from rbf.pde.nodes import poisson_disc_nodes
from rbf.pde.nodes import min_energy_nodes
from rbf.pde.geometry import contains

######################
###   Geometry    ###
######################

# vertices and simplices for a "courtyard" geometry.
# Five first vertices : Exterior domain

vertices = np.array([[  0.,   0.],
                     [125.,   0.],
                     [125., 100.],
                     [  0., 100.],
                     [  0.,   0.],
                     [ 40.,  30.],
                     [ 80.,  30.],
                     [ 80.,  70.],
                     [ 40.,  70.],
                     [ 40.,  30.],
                     [ 45.,  35.],
                     [ 75.,  35.],
                     [ 75.,  65.],
                     [ 45.,  65.],
                     [ 45.,  35.]])

simplices = np.array([[ 0,  1],
                     [ 1,  2],
                     [ 2,  3],
                     [ 3,  4],
                     [ 5,  6],
                     [ 6,  7],
                     [ 7,  8],
                     [ 8,  9],
                     [10, 11],
                     [11, 12],
                     [12, 13],
                     [13, 14]])

ext_simplices = np.array([[ 0,  1],
                          [ 1,  2],
                          [ 2,  3],
                          [ 3,  4]])

# Identify which simplices belong to the interior and which belong to the
# exterior
boundary_groups = {
    'exterior': np.arange(len(ext_simplices)),
    'interior': np.arange(len(ext_simplices), len(simplices)),
    }

##### Domain building ###########

N_nodes = 6000
nodes, groups, normals = min_energy_nodes(N_nodes, 
                                          (vertices, simplices),
                                          boundary_groups=boundary_groups,
                                          boundary_groups_with_ghosts=['interior'])

### diffusion parameters ###
# Diffusion
Diff_x = 100 # m^2/s
Diff_y = 100 # m^2/s

# Source term parameters
source_idx = 887
x_s_n, y_s_n = 130.23213463982668, 150.413853115689
As = 1e3 # amplitude source

pos_source = source_idx

########## RBF simulation ###########

phi = 'phs5'
stencil_size = 45
order = 7

print("Solving ...")
tic = time.perf_counter()

# Enforce that the Lapacian is 0 at the interior nodes (not to be confused
# with the nodes on the interior boundary)
D_laplacian = weight_matrix(
    nodes[groups['interior']],
    nodes,
    stencil_size,
    [[2, 0], [0, 2]],
        coeffs=[
        Diff_x,
        Diff_y
        ],
    phi=phi,
    order=order
    )

# source term marked by a cross in graph
b_interior = np.full(len(groups['interior']), 0)
b_interior[pos_source] = As

# Enforce that u = 0 at the exterior boundary
A_boundary_exterior = weight_matrix(
    nodes[groups['boundary:exterior']],
    nodes,
    stencil_size,
    [0, 0],
    phi=phi,
    order=order
    )

b_boundary_exterior =  np.full(len(groups['boundary:exterior']), 0) 

# Enforce a free boundary at the interior boundary nodes. NEUMANN : $\nabla u \cdot n = 0$
A_boundary_interior = weight_matrix(
    nodes[groups['boundary:interior']],
    nodes,
    stencil_size,
    [[1, 0], [0, 1]],
    coeffs=[
        normals[groups['boundary:interior'], 0],
        normals[groups['boundary:interior'], 1]
        ],
    phi=phi,
    order=order
    )

b_boundary_interior = np.zeros(len(groups['boundary:interior']))

# Use the ghost nodes to enforce that the Laplacian is 0 at the interior
# boundary nodes.

A_ghosts_interior = weight_matrix(
    nodes[groups['boundary:interior']],
    nodes,
    stencil_size,
    [[2, 0], [0, 2]],
    phi=phi,
    order=order
    )

b_ghosts_interior = np.full(len(groups['ghosts:interior']), 0)

# Combine the LHS and RHS components and solve
A = sp.vstack(
    (- D_laplacian, A_boundary_exterior, A_boundary_interior, A_ghosts_interior)
    )

b = np.hstack(
    (b_interior, b_boundary_exterior, b_boundary_interior, b_ghosts_interior)
    )

soln = sp.linalg.spsolve(A, b)

toc = time.perf_counter()

print(f"ellapsed time = {toc - tic} s")

#%% plot solution
# The rest is just plotting...

# %matplotlib qt

import matplotlib
import matplotlib.colors as colors

fig, ax = plt.subplots(figsize=(8, 8))

fontsize = 12
font = {'size'   : fontsize}
matplotlib.rc('font', **font)

for smp in simplices:
    ax.plot(vertices[smp, 0], vertices[smp, 1], 'k-')
    
p = ax.scatter(nodes[groups['interior']][:, 0], nodes[groups['interior']][:, 1],
               s=10,
               c=soln[groups['interior']], cmap='jet',
               norm=colors.LogNorm(vmin= 1e-1, vmax = int(np.max(1.1*soln))))

fig.colorbar(p)
ax.grid(ls=':')
ax.set_aspect('equal')

x_s, y_s = nodes[groups['interior']][pos_source]
ax.plot(x_s, y_s, marker = 'x', markersize=12, linewidth = 20, label = "source")
ax.legend(loc = 'upper right')

nb_nodes = 'N =' + str(N_nodes)
ax.set_title('           Solution at nodes' + ' $' + nb_nodes + '$ \n'
                          + '$\phi $ = ' f'{phi}, order = {order},\n'
                           f'stencil_size = {stencil_size}')

fig.show()

#%% plot domain

fig1, ax1 = plt.subplots()
for smp in simplices:
    ax1.plot(vertices[smp, 0], vertices[smp, 1], 'k-')

for name, idx in groups.items():
    ax1.plot(nodes[idx, 0], nodes[idx, 1], '.', label=name)
ax1.grid(ls=':')
ax1.set_aspect('equal')
ax1.legend(loc = 'upper right')
ax1.set_title('Node groups')

fig1.show()

Best regards,
Roman

Improve speed of RBF-interpolation

Hello Mr. Hines,

I am trying to interpolate a scattered set of data points in 3D (x, y, z, phi) to a regular rectangular 3D grid in a "smooth" manner, i.e. with derivative continuity Using RBFInterpolant, I tend to get pretty accurate performance, but I wanted to know how to improve the speed of the process. My scattered dataset is around 10^4 x, y, z values (x_obs = (52850,3) ; u_obs = (52850,1)) and I want to interpolate them to 10^6 regular grid points (x_itp = 100^3), i.e. a mesh of 100 grid points on each of x, y and z axis.

Currently, it's taking more than 30 mins to perform the interpolation process. I observed that you are using K-NN. Is it this part that's taking the maximum time? Or is it the LU decomposition part? What is the bottleneck? Could you suggest me ways to speed up the performance?

A separate issue is related to memory. When used for x_obs = (225000,3) scattered points, I am getting the error :

_'numpy.core.exceptions.MemoryError: Unable to allocate 377. GiB for an array with shape (225044, 225044) and data type float64'

Is there a way to bypass this?

Thanks in advance,
Paul

How to compute anisotropic diffusion operator ?

Hello Mister Hines,

I am still working with RBF-FD thanks to your package. I read on the issues posted here how to compute a pressure field given some velocities. In this pressure Poisson equation, the right handside was computed with the use of weight matrices :

Wx = weight_matrix(nodes, nodes, n, [1, 0, 0], phi=phi, order=order)
Wy = weight_matrix(nodes, nodes, n, [0, 1, 0], phi=phi, order=order)
Wz = weight_matrix(nodes, nodes, n, [0, 0, 1], phi=phi, order=order)
Wxx = weight_matrix(nodes, nodes, n, [2, 0, 0], phi=phi, order=order)
Wyy = weight_matrix(nodes, nodes, n, [0, 2, 0], phi=phi, order=order)
Wzz = weight_matrix(nodes, nodes, n, [0, 0, 2], phi=phi, order=order)
bx = -rho*(u*Wx.dot(u) + v*Wy.dot(u) + w*Wz.dot(u)) + mu*(Wxx.dot(u) + Wyy.dot(u) + Wzz.dot(u))
by = -rho*(u*Wx.dot(v) + v*Wy.dot(v) + w*Wz.dot(v)) + mu*(Wxx.dot(v) + Wyy.dot(v) + Wzz.dot(v))
bz = -rho*(u*Wx.dot(w) + v*Wy.dot(w) + w*Wz.dot(w)) + mu*(Wxx.dot(w) + Wyy.dot(w) + Wzz.dot(w))
rhs = Wx.dot(bx) + Wy.dot(by) + Wz.dot(bz)

My question is the following :

  • What is the best way to build weight matrix on this kind of equation :

$$ \mathbf{W} = \partial_j (D_j \partial_{j}) $$

For example in dimension 3, building $W : (n_{interior}, n)$ a weight matrix build on some interior nodes (not affected by boundary conditions), with $n_{interior}$ number of interior points and $n$ the total number of points,
so that,

$$ W u = \partial_x (D_x \partial_x u) + \partial_y (D_y \partial_y u) + \partial_z (D_z \partial_z u) $$

With $D_x$, $D_y$, $D_z$ of dimensions $(n_{interior},1)$ each, and $u$ a scalar variable of dimension $(n,1)$ defined on whole domain.

In this example I cannot use the method showed in the example to compute the RHS because I don't have access to variable $u$ to make the writings work with dimensions of matrices.

Do you have any hint about how to build an anisotropic diffusion operator in that case ?

Kind regards,
Roman

Install trouble with gcc

Hi @treverhines. I'm excited to try out your RBF package, but am having trouble with the install step.

The error:

nlogan-lt1:RBF nlogan$ python setup.py install
Compiling rbf/halton.pyx because it changed.
Compiling rbf/misc/bspline.pyx because it changed.
Compiling rbf/geometry.pyx because it changed.
Compiling rbf/poly.pyx because it changed.
[1/4] Cythonizing rbf/geometry.pyx
[2/4] Cythonizing rbf/halton.pyx
[3/4] Cythonizing rbf/misc/bspline.pyx
[4/4] Cythonizing rbf/poly.pyx
running install
running bdist_egg
running egg_info
creating RBF.egg-info
writing RBF.egg-info/PKG-INFO
writing top-level names to RBF.egg-info/top_level.txt
writing dependency_links to RBF.egg-info/dependency_links.txt
writing manifest file 'RBF.egg-info/SOURCES.txt'
reading manifest file 'RBF.egg-info/SOURCES.txt'
writing manifest file 'RBF.egg-info/SOURCES.txt'
installing library code to build/bdist.macosx-10.9-x86_64/egg
running install_lib
running build_py
creating build
creating build/lib.macosx-10.9-x86_64-2.7
creating build/lib.macosx-10.9-x86_64-2.7/rbf
copying rbf/__init__.py -> build/lib.macosx-10.9-x86_64-2.7/rbf
copying rbf/basis.py -> build/lib.macosx-10.9-x86_64-2.7/rbf
copying rbf/domain.py -> build/lib.macosx-10.9-x86_64-2.7/rbf
copying rbf/fd.py -> build/lib.macosx-10.9-x86_64-2.7/rbf
copying rbf/fdbuild.py -> build/lib.macosx-10.9-x86_64-2.7/rbf
copying rbf/gauss.py -> build/lib.macosx-10.9-x86_64-2.7/rbf
copying rbf/interpolate.py -> build/lib.macosx-10.9-x86_64-2.7/rbf
copying rbf/linalg.py -> build/lib.macosx-10.9-x86_64-2.7/rbf
copying rbf/mp.py -> build/lib.macosx-10.9-x86_64-2.7/rbf
copying rbf/nodes.py -> build/lib.macosx-10.9-x86_64-2.7/rbf
copying rbf/stencil.py -> build/lib.macosx-10.9-x86_64-2.7/rbf
copying rbf/utils.py -> build/lib.macosx-10.9-x86_64-2.7/rbf
creating build/lib.macosx-10.9-x86_64-2.7/rbf/misc
copying rbf/misc/__init__.py -> build/lib.macosx-10.9-x86_64-2.7/rbf/misc
copying rbf/misc/filter.py -> build/lib.macosx-10.9-x86_64-2.7/rbf/misc
copying rbf/misc/formulation.py -> build/lib.macosx-10.9-x86_64-2.7/rbf/misc
copying rbf/misc/integrate.py -> build/lib.macosx-10.9-x86_64-2.7/rbf/misc
running build_ext
building 'rbf.halton' extension
creating build/temp.macosx-10.9-x86_64-2.7
creating build/temp.macosx-10.9-x86_64-2.7/rbf
gcc -fno-strict-aliasing -I/Users/nlogan/Code/miniconda2/include -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I/Users/nlogan/Code/miniconda2/lib/python2.7/site-packages/numpy/core/include -I/Users/nlogan/Code/miniconda2/include/python2.7 -c rbf/halton.c -o build/temp.macosx-10.9-x86_64-2.7/rbf/halton.o
In file included from /Users/nlogan/Code/miniconda2/lib/gcc/x86_64-apple-darwin11.4.2/4.8.5/include-fixed/syslimits.h:7:0,
                 from /Users/nlogan/Code/miniconda2/lib/gcc/x86_64-apple-darwin11.4.2/4.8.5/include-fixed/limits.h:34,
                 from /Users/nlogan/Code/miniconda2/include/python2.7/Python.h:19,
                 from rbf/halton.c:23:
/Users/nlogan/Code/miniconda2/lib/gcc/x86_64-apple-darwin11.4.2/4.8.5/include-fixed/limits.h:168:61: fatal error: limits.h: No such file or directory
 #include_next <limits.h>  /* recurse down to the real one */
                                                             ^
compilation terminated.
error: command 'gcc' failed with exit status 1

Background: I use conda, and got gcc through conda after an initial fail using whatever other gcc I had before (same error). My conda list is:

nlogan-lt1:RBF nlogan$ conda list
# packages in environment at /Users/nlogan/Code/miniconda2:
#
# Name                    Version                   Build  Channel
absl-py                   0.2.2                      py_0    conda-forge
alabaster                 0.7.11                   py27_2    conda-forge
anaconda-client           1.6.14                     py_0    conda-forge
appnope                   0.1.0                    py27_0    conda-forge
apptools                  4.4.0                    py27_0    conda-forge
asn1crypto                0.24.0                   py27_0    conda-forge
asteval                   0.9.12                   py27_0    conda-forge
astor                     0.6.2                      py_0    conda-forge
astropy                   2.0.7                    py27_1    conda-forge
atomicwrites              1.1.5                    py27_0    conda-forge
attrs                     18.1.0                     py_1    conda-forge
babel                     2.5.3                    py27_0    conda-forge
backports                 1.0                      py27_1    conda-forge
backports.functools_lru_cache 1.5                      py27_0    conda-forge
backports.shutil_get_terminal_size 1.0.0                      py_3    conda-forge
backports.weakref         1.0rc1                   py27_1    conda-forge
backports_abc             0.5                      py27_0    conda-forge
beautifulsoup4            4.6.0                    py27_0    conda-forge
bibtexparser              1.0.1                    py27_0    conda-forge
blas                      1.1                    openblas    conda-forge
bleach                    1.5.0                    py27_0    conda-forge
blosc                     1.14.0                        1    conda-forge
bokeh                     0.12.16                  py27_0    conda-forge
boto3                     1.7.48                     py_0    conda-forge
botocore                  1.10.48                    py_0    conda-forge
bottleneck                1.2.1            py27h7eb728f_1    conda-forge
bzip2                     1.0.6                         1    conda-forge
ca-certificates           2018.4.16                     0    conda-forge
certifi                   2018.4.16                py27_0    conda-forge
cffi                      1.11.5                   py27_0    conda-forge
cftime                    1.0.0                    py27_0    conda-forge
chaospy                   2.3.2                      py_0    conda-forge
chardet                   3.0.4                    py27_0    conda-forge
clangdev                  6.0.0                 default_0    conda-forge
click                     6.7                        py_1    conda-forge
cloog                     0.18.0                        0
cloudpickle               0.5.3                      py_0    conda-forge
clyent                    1.2.2                    py27_0    conda-forge
conda                     4.5.8                    py27_1    conda-forge
conda-build               3.10.9                   py27_0    conda-forge
conda-env                 2.6.0                         0    conda-forge
conda-verify              2.0.0                    py27_0    conda-forge
configobj                 5.0.6                    py27_0
contextlib2               0.5.5                    py27_1    conda-forge
corner                    2.0.1                    py27_0    conda-forge
cryptography              2.2.1                    py27_0    conda-forge
curl                      7.60.0               h93b3f91_0    conda-forge
cycler                    0.10.0                   py27_0    conda-forge
cyordereddict             1.0.0                    py27_1    conda-forge
Cython                    0.28.3                    <pip>
cytoolz                   0.9.0.1                  py27_0    conda-forge
dask                      0.17.5                     py_0    conda-forge
dask-core                 0.17.5                     py_0    conda-forge
decorator                 4.3.0                      py_0    conda-forge
dicttoxml                 1.7.4                    py27_0    conda-forge
dill                      0.2.8.2                  py27_0    conda-forge
distributed               1.21.8                   py27_0    conda-forge
docutils                  0.14                     py27_0    conda-forge
emcee                     2.2.1                    py27_3    conda-forge
enum34                    1.1.6                    py27_1    conda-forge
envisage                  4.5.1                    py27_0    conda-forge
expat                     2.2.5                         0    conda-forge
fann2                     2.2.0                         0    conda-forge
filelock                  3.0.4                    py27_0    conda-forge
fortranformat             0.2.5                     <pip>
fortranformat             0.2.5                      py_0    conda-forge
freetds                   1.00.44                       2    conda-forge
freetype                  2.8.1                         0    conda-forge
funcsigs                  1.0.2                      py_2    conda-forge
functools32               3.2.3.2                  py27_2    conda-forge
future                    0.16.0                   py27_0    conda-forge
futures                   3.2.0                    py27_0    conda-forge
gast                      0.2.0                      py_0    conda-forge
gcc                       4.8.5                         8
geos                      3.6.2                hfc679d8_2    conda-forge
git                       2.18.0                        0    conda-forge
glob2                     0.6                        py_0    conda-forge
gmp                       6.1.2                hfc679d8_0    conda-forge
gpr1d                     1.0.1                    py27_0    omfit
gpr1dfusion               1.0.1                      py_0    aaronkho
gptools                   0.2.3            py27h7eb728f_0    conda-forge
grpcio                    1.12.1           py27hd9629dc_0
h5netcdf                  0.6.1                      py_0    conda-forge
h5py                      2.8.0            py27h470a237_0    conda-forge
hdf4                      4.2.13                        0    conda-forge
hdf5                      1.10.1                        2    conda-forge
heapdict                  1.0.0                    py27_0    conda-forge
html5lib                  0.9999999                py27_0    conda-forge
icu                       58.2                 hfc679d8_0    conda-forge
idna                      2.7                      py27_0    conda-forge
imagesize                 1.0.0                    py27_0    conda-forge
imbalanced-learn          0.3.3                      py_0    conda-forge
intel-openmp              2018.0.3                      0
ipaddress                 1.0.22                     py_1    conda-forge
ipython                   5.7.0                    py27_0    conda-forge
ipython_genutils          0.2.0                    py27_0    conda-forge
isl                       0.12.2                        1
jedi                      0.12.0                   py27_0    conda-forge
jinja2                    2.10                     py27_0    conda-forge
jmespath                  0.9.3                    py27_0    conda-forge
jpeg                      9b                            2    conda-forge
jsoncpp                   1.8.1                h2d50403_1    conda-forge
jsonschema                2.6.0                    py27_1    conda-forge
jupyter_core              4.4.0                      py_0    conda-forge
kiwisolver                1.0.1                    py27_1    conda-forge
krb5                      1.14.6                        0    conda-forge
libcxx                    6.0.0                         0    conda-forge
libcxxabi                 4.0.1                hebd6815_0
libedit                   3.1.20170329                  0    conda-forge
libffi                    3.2.1                         3    conda-forge
libgfortran               3.0.1                h93005f0_2
libgfortran-ng            3.0.1                h93005f0_2
libiconv                  1.15                 h470a237_1    conda-forge
libnetcdf                 4.6.1                         2    conda-forge
libopenblas               0.2.20               hdc02c5d_7
libpng                    1.6.34                        0    conda-forge
libpq                     9.6.3                         0    conda-forge
libprotobuf               3.5.2                         0    conda-forge
libssh2                   1.8.0                h5b517e9_2    conda-forge
libtiff                   4.0.9                he6b73bb_0    conda-forge
libuuid                   1.0.3                         1    conda-forge
libxml2                   2.9.8                         0    conda-forge
libxslt                   1.1.32                        0    conda-forge
linecache2                1.0.0                    py27_0    conda-forge
llvm-meta                 6.0.0                         0    conda-forge
llvmdev                   6.0.0                 default_3    conda-forge
lmfit                     0.9.10           py27h24bf2e0_0    conda-forge
locket                    0.2.0                    py27_1    conda-forge
markdown                  2.6.11                     py_0    conda-forge
markupsafe                1.0                      py27_0    conda-forge
matplotlib                2.1.2                    py27_0    conda-forge
mayavi                    4.5.0                    py27_0
mdsplus                   7.7.9                    py27_1    omfit
mkl                       2018.0.3                      1
mkl_fft                   1.0.2                    py27_0    conda-forge
mkl_random                1.0.1                    py27_0    conda-forge
mock                      2.0.0                    py27_0    conda-forge
more-itertools            4.2.0                      py_0    conda-forge
mpc                       1.1.0                         4    conda-forge
mpfr                      3.1.5                         0    conda-forge
mpi                       1.0                     openmpi    conda-forge
mpi4py                    3.0.0            py27_openmpi_2    conda-forge
mpmath                    1.0.0                      py_0    conda-forge
msgpack-python            0.5.6            py27h2d50403_2    conda-forge
nbformat                  4.4.0                    py27_0    conda-forge
ncurses                   5.9                          10    conda-forge
netcdf4                   1.4.0                    py27_0    conda-forge
networkx                  2.1                      py27_0    conda-forge
nlopt                     2.4.2                    py27_2    conda-forge
numexpr                   2.6.5                    py27_0    conda-forge
numpy                     1.14.5          py27_blas_openblashd3ea46f_201  [blas_openblas]  conda-forge
numpy-base                1.14.3           py27h7ef55bc_1
omas                      0.14.0                     py_0    conda-forge
omfit                     0.25.8.3                 py27_1    omfit
omfit                     0.0.0                     <pip>
openblas                  0.2.20                        8    conda-forge
openmotif                 2.3.7                         0    conda-forge
openmpi                   3.1.0                         1    conda-forge
openssl                   1.0.2o                        0    conda-forge
packaging                 17.1                       py_0    conda-forge
pandas                    0.23.1                   py27_0    conda-forge
parso                     0.3.0                      py_0    conda-forge
partd                     0.3.8                    py27_0    conda-forge
pathlib2                  2.3.2                    py27_0    conda-forge
patsy                     0.5.0                    py27_0    conda-forge
pbr                       4.0.4                      py_0    conda-forge
pexpect                   4.6.0                    py27_0    conda-forge
pickleshare               0.7.4                    py27_0    conda-forge
pidly                     0.2.7                    py27_0    conda-forge
pip                       10.0.1                    <pip>
pip                       9.0.3                    py27_0    conda-forge
pkginfo                   1.4.2                    py27_0    conda-forge
pluggy                    0.6.0                      py_0    conda-forge
postgresql                10.4             py27ha98c86b_0    conda-forge
prompt_toolkit            1.0.15                   py27_0    conda-forge
protobuf                  3.5.2                    py27_0    conda-forge
psutil                    5.4.6                    py27_0    conda-forge
psycopg2                  2.7.5                    py27_0    conda-forge
ptyprocess                0.6.0                    py27_0    conda-forge
py                        1.5.4                      py_0    conda-forge
py-fann2                  1.1.2                    py27_0    conda-forge
pycosat                   0.6.3                    py27_0    conda-forge
pycparser                 2.18                     py27_0    conda-forge
pyface                    6.0.0                      py_1    conda-forge
pygments                  2.2.0                    py27_0    conda-forge
pyodbc                    4.0.23           py27hfc679d8_0    conda-forge
pyopenssl                 18.0.0                   py27_0    conda-forge
pyparsing                 2.2.0                    py27_0    conda-forge
pyqt                      4.11.4                   py27_2    conda-forge
pysocks                   1.6.8                    py27_1    conda-forge
pytables                  3.4.4                    py27_8    conda-forge
pytest                    3.6.2                    py27_0    conda-forge
python                    2.7.15                        0    conda-forge
python-dateutil           2.7.3                      py_0    conda-forge
python.app                1.2                      py27_0    conda-forge
pyttk                     0.3.2                     <pip>
pyttk                     0.3.2                      py_0    conda-forge
pytz                      2018.4                     py_0    conda-forge
pyyaml                    3.12                     py27_1    conda-forge
qt                        4.8.7                         4
readline                  7.0                           0    conda-forge
reindent                  0.1.1                    py27_0    conda-forge
requests                  2.19.1                   py27_0    conda-forge
ruamel_yaml               0.15.44          py27h470a237_0    conda-forge
s3transfer                0.1.13                   py27_0    conda-forge
scandir                   1.7                      py27_0    conda-forge
scikit-learn              0.19.2          py27_blas_openblas_200  [blas_openblas]  conda-forge
scipy                     1.1.0           py27_blas_openblashd3ea46f_201  [blas_openblas]  conda-forge
seaborn                   0.8.1                    py27_0    conda-forge
setuptools                39.2.0                   py27_0    conda-forge
shapely                   1.6.4            py27h164cb2d_1    conda-forge
simplegeneric             0.8.1                    py27_0    conda-forge
singledispatch            3.4.0.3                  py27_0    conda-forge
sip                       4.18                     py27_1    conda-forge
six                       1.11.0                   py27_1    conda-forge
snowballstemmer           1.2.1                    py27_0    conda-forge
sortedcontainers          2.0.4                    py27_0    conda-forge
sphinx                    1.6.7                    py27_0    conda-forge
sphinx_bootstrap_theme    0.6.4                      py_0    conda-forge
sphinxcontrib-websupport  1.1.0                    py27_0    conda-forge
sqlite                    3.20.1                        2    conda-forge
statsmodels               0.9.0                    py27_0    conda-forge
subprocess32              3.5.2                    py27_0    conda-forge
tbb                       2018_20171205                 0    conda-forge
tblib                     1.3.2                    py27_0    conda-forge
tensorboard               1.8.0                    py27_1    conda-forge
tensorflow                1.8.0                    py27_1    conda-forge
termcolor                 1.1.0                    py27_1    conda-forge
tk                        8.6.7                         0    conda-forge
toolz                     0.9.0                      py_0    conda-forge
tornado                   5.0.2                    py27_0    conda-forge
traceback2                1.4.0                    py27_0    conda-forge
traitlets                 4.3.2                    py27_0    conda-forge
traits                    4.6.0                    py27_1    conda-forge
traitsui                  6.0.0                      py_1    conda-forge
typing                    3.6.4                    py27_0    conda-forge
uncertainties             3.0.2                    py27_1    conda-forge
unittest2                 1.1.0                      py_0    conda-forge
unixodbc                  2.3.4                         1    conda-forge
urllib3                   1.23                     py27_0    conda-forge
vtk                       8.1.0           py27h3f2a929_203    conda-forge
wcwidth                   0.1.7                    py27_0    conda-forge
webencodings              0.5.1                    py27_0    conda-forge
werkzeug                  0.14.1                     py_0    conda-forge
wget                      1.19.5               hf30b1f0_0
wheel                     0.31.0                   py27_0    conda-forge
xarray                    0.10.7                   py27_0    conda-forge
xmltodict                 0.11.0                   py27_0    conda-forge
xz                        5.2.3                         0    conda-forge
yaml                      0.1.7                         0    conda-forge
zict                      0.1.3                      py_0    conda-forge
zlib                      1.2.11               h470a237_3    conda-forge

Let me know if there is some dependency I am not satisfying.

Discrepancy with scipy Rbf interpolation when using Gaussian basis

Hello,

I get very different results when interpolating with RBF and scipy.Rbf using gaussian basis.
I noticed that RBF and Scipy use different definition for what is called 'gaussian' basis, but even if I use the scipy basis expression in RBF, the results are different. The code below shows the different. Any help is much appreciated.


# coding: utf-8

# In[1]:


import random
import numpy as np
from scipy.interpolate import Rbf
import rbf
from rbf.interpolate import RBFInterpolant
from rbf.pde.nodes import poisson_disc_nodes
import matplotlib.pyplot as plt
from matplotlib import cm


# In[5]:


grid_spacing     = 40.0
peak = 10.0

area_dimension = 100 + float(grid_spacing) / 2.0
vert = np.array([[-area_dimension,-area_dimension],[-area_dimension,area_dimension],
                    [area_dimension,area_dimension],[area_dimension,-area_dimension]])
smp = np.array([[0,1],[1,2],[2,3],[3,0]])


nodes, groups, _ = poisson_disc_nodes(float(grid_spacing), (vert, smp))

fig, ax = plt.subplots()
ax.plot(nodes[:, 0], nodes[:, 1], 'ko', markersize=4)


# In[7]:


x_obs = nodes
u_obs = peak * np.ones(len(x_obs))

ip2  = Rbf(x_obs[:,0], x_obs[:,1], u_obs, function='gaussian', sigma=0.1,  epsilon=grid_spacing/2.71828)

area_x = np.arange(-100, 100, 1)
area_y = np.arange(-100, 100, 1)

xx, yy = np.meshgrid(area_x, area_y, indexing='ij')
zz2 = ip2(xx, yy)

plt.pcolor(xx, yy, zz2,cmap=cm.jet)
plt.scatter(x_obs[:,0], x_obs[:,1], u_obs, cmap=cm.jet)
ax = plt.gca()
ax.set_aspect('equal')


# In[9]:


x_obs = nodes
u_obs = peak * np.ones(len(x_obs))


from rbf.basis import *
r = get_r()
eps = get_eps()
ga_expr = sympy.exp(-(r/eps)**2)
ga = RBF(ga_expr)

ip1  = RBFInterpolant(x_obs, u_obs, phi=ga, sigma=0.1, eps=grid_spacing/2.)

arena_x = np.arange(-100, 100, 1)
arena_y = np.arange(-100, 100, 1)

xx, yy = np.meshgrid(arena_x, arena_y)
coords = np.column_stack((xx.ravel(), yy.ravel()))
zz1 = ip1(coords)
plt.pcolor(xx, yy, zz1.reshape(xx.shape), cmap=cm.jet)
plt.scatter(x_obs[:,0], x_obs[:,1], u_obs, cmap=cm.jet)
ax = plt.gca()
ax.set_aspect('equal')

Generating weight matrices for different derivatives simultaneously

Is there a way to get fd.weight_matrix to produce matrices for, say, [1,0] and [0,1] at the same time? Not as a sum, but as two different operations. Under the hood, it would just be different right hand sides for the same core RBF matrix-vector system for each stencil. Solving against multiple right hand sides as a tall, skinny matrix should be much faster than re-inverting the system in multiple fd.weight_matrix calls.

See e.g. Appendix B of Flyer, Barnett & Wicker 2016 https://doi.org/10.1016/j.jcp.2016.02.078 where they do it this way in their MATLAB implementation.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.