Beispiel #1
0
def elastic3d_displacement(x, p, n, **kwargs):
    '''
    Returns weight matrices that map displacements at `p` to the displacements
    at `x`.

    Parameters
    ----------
    x: (N, 3) array
        target points.

    p: (M, 3) array
        observation points.

    n : int
        stencil size

    **kwargs:
        additional arguments passed to `weight_matrix`

    Returns
    -------
    dict
        keys are the components and the values are the corresponding weight
        matrices.

    '''
    D_xx = weight_matrix(x, p, n, (0, 0, 0), **kwargs)
    D_yy = weight_matrix(x, p, n, (0, 0, 0), **kwargs)
    D_zz = weight_matrix(x, p, n, (0, 0, 0), **kwargs)
    return {'xx': D_xx, 'yy': D_yy, 'zz': D_zz}
Beispiel #2
0
def elastic2d_surface_force(x, nrm, p, n, lamb=1.0, mu=1.0, **kwargs):
    '''
    Returns weight matrices that map displacements at `p` to the surface
    traction force at `x` with normals `nrm` in a two-dimensional (plane
    strain) homogeneous elastic medium.

    Parameters
    ----------
    x: (N, 2) array
        target points which reside on a surface.

    nrm: (N, 2) array
        surface normal vectors at each point in `x`.

    p: (M, 2) array
        observation points.

    n : int
        stencil size

    lamb, mu: float
        Lame parameters

    **kwargs:
        additional arguments passed to `weight_matrix`

    Returns
    -------
    dict
        keys are the components and the values are the corresponding weight
        matrices.

    '''
    # x component of traction force resulting from x displacement
    coeffs_xx = [nrm[:, 0] * (lamb + 2 * mu), nrm[:, 1] * mu]
    diffs_xx = [(1, 0), (0, 1)]
    # x component of traction force resulting from y displacement
    coeffs_xy = [nrm[:, 0] * lamb, nrm[:, 1] * mu]
    diffs_xy = [(0, 1), (1, 0)]
    # y component of traction force resulting from x displacement
    coeffs_yx = [nrm[:, 0] * mu, nrm[:, 1] * lamb]
    diffs_yx = [(0, 1), (1, 0)]
    # y component of force resulting from displacement in the y direction
    coeffs_yy = [nrm[:, 0] * mu, nrm[:, 1] * (lamb + 2 * mu)]
    diffs_yy = [(1, 0), (0, 1)]
    # make the differentiation matrices that enforce the free surface boundary
    # conditions.
    D_xx = weight_matrix(x, p, n, diffs_xx, coeffs=coeffs_xx, **kwargs)
    D_xy = weight_matrix(x, p, n, diffs_xy, coeffs=coeffs_xy, **kwargs)
    D_yx = weight_matrix(x, p, n, diffs_yx, coeffs=coeffs_yx, **kwargs)
    D_yy = weight_matrix(x, p, n, diffs_yy, coeffs=coeffs_yy, **kwargs)
    return {'xx': D_xx, 'xy': D_xy, 'yx': D_yx, 'yy': D_yy}
Beispiel #3
0
def elastic2d_body_force(x, p, n, lamb=1.0, mu=1.0, **kwargs):
    ''' 
  Returns weight matrices that map displacements at `p` to the body
  force at `x` in a two-dimensional (plane strain) homogeneous elastic
  medium

  Parameters
  ----------
  x : (N, 2) array
    Target points.
  
  p : (M, 2) array
    Observation points.  
  
  n : int
    stencil size    
  
  lamb, mu : float, optional
    Lame parameters
  
  **kwargs :
    additional arguments passed to `weight_matrix`

  Returns
  -------
  dict
    keys are the components and the values are the corresponding
    weight matrices.

  '''
    # x component of force resulting from displacement in the x direction.
    coeffs_xx = [lamb + 2 * mu, mu]
    diffs_xx = [(2, 0), (0, 2)]
    # x component of force resulting from displacement in the y direction.
    coeffs_xy = [lamb + mu]
    diffs_xy = [(1, 1)]
    # y component of force resulting from displacement in the x direction.
    coeffs_yx = [lamb + mu]
    diffs_yx = [(1, 1)]
    # y component of force resulting from displacement in the y direction.
    coeffs_yy = [lamb + 2 * mu, mu]
    diffs_yy = [(0, 2), (2, 0)]
    # make the differentiation matrices that enforce the PDE on the
    # interior nodes.
    D_xx = weight_matrix(x, p, n, diffs_xx, coeffs=coeffs_xx, **kwargs)
    D_xy = weight_matrix(x, p, n, diffs_xy, coeffs=coeffs_xy, **kwargs)
    D_yx = weight_matrix(x, p, n, diffs_yx, coeffs=coeffs_yx, **kwargs)
    D_yy = weight_matrix(x, p, n, diffs_yy, coeffs=coeffs_yy, **kwargs)
    return {'xx': D_xx, 'xy': D_xy, 'yx': D_yx, 'yy': D_yy}
Beispiel #4
0
groups['interior+boundary:all'] = np.hstack(
    (groups['interior'], groups['boundary:all']))

# create the initial displacements at the interior and boundary, the velocities
# are zero
r = np.sqrt((nodes[groups['interior+boundary:all'], 0] - 0.5)**2 +
            (nodes[groups['interior+boundary:all'], 1] - 0.5)**2)

u_init = np.zeros((n, ))
u_init[groups['interior+boundary:all']] = 1.0 / (1 + (r / 0.1)**4)
v_init = np.zeros((n, ))
z_init = np.hstack((u_init, v_init))

# construct a matrix that maps the displacements at `nodes` to `u`
B_disp = weight_matrix(x=nodes[groups['interior+boundary:all']],
                       p=nodes,
                       n=1,
                       diffs=(0, 0))
B_free = weight_matrix(x=nodes[groups['boundary:all']],
                       p=nodes,
                       n=stencil_size,
                       diffs=[(1, 0), (0, 1)],
                       coeffs=[
                           normals[groups['boundary:all'], 0],
                           normals[groups['boundary:all'], 1]
                       ],
                       phi=phi,
                       order=order)
B = expand_rows(B_disp, groups['interior+boundary:all'], n)
B += expand_rows(B_free, groups['ghosts:all'], n)
B = B.tocsc()
Bsolver = splu(B)
Beispiel #5
0
## Enforce the PDE on interior nodes AND the free surface nodes 
# x component of force resulting from displacement in the x direction.
coeffs_xx = [lamb+2*mu, mu]
diffs_xx = [(2, 0), (0, 2)]
# x component of force resulting from displacement in the y direction.
coeffs_xy = [lamb, mu]
diffs_xy = [(1, 1), (1, 1)]
# y component of force resulting from displacement in the x direction.
coeffs_yx = [mu, lamb]
diffs_yx = [(1, 1), (1, 1)]
# y component of force resulting from displacement in the y direction.
coeffs_yy = [lamb+2*mu, mu]
diffs_yy =  [(0, 2), (2, 0)]
# make the differentiation matrices that enforce the PDE on the 
# interior nodes.
D_xx = weight_matrix(nodes[groups['interior']], nodes, n, diffs_xx, coeffs=coeffs_xx)
D_xy = weight_matrix(nodes[groups['interior']], nodes, n, diffs_xy, coeffs=coeffs_xy)
D_yx = weight_matrix(nodes[groups['interior']], nodes, n, diffs_yx, coeffs=coeffs_yx)
D_yy = weight_matrix(nodes[groups['interior']], nodes, n, diffs_yy, coeffs=coeffs_yy)
G_xx = add_rows(G_xx, D_xx, groups['interior'])
G_xy = add_rows(G_xy, D_xy, groups['interior'])
G_yx = add_rows(G_yx, D_yx, groups['interior'])
G_yy = add_rows(G_yy, D_yy, groups['interior'])

# use the ghost nodes to enforce the PDE on the boundary
D_xx = weight_matrix(nodes[groups['boundary:free']], nodes, n, diffs_xx, coeffs=coeffs_xx)
D_xy = weight_matrix(nodes[groups['boundary:free']], nodes, n, diffs_xy, coeffs=coeffs_xy)
D_yx = weight_matrix(nodes[groups['boundary:free']], nodes, n, diffs_yx, coeffs=coeffs_yx)
D_yy = weight_matrix(nodes[groups['boundary:free']], nodes, n, diffs_yy, coeffs=coeffs_yy)
G_xx = add_rows(G_xx, D_xx, groups['ghosts:free'])
G_xy = add_rows(G_xy, D_xy, groups['ghosts:free'])
Beispiel #6
0
# 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 "left hand side" matrix.
# create the component which evaluates the PDE
A_interior = weight_matrix(nodes[groups['interior']],
                           nodes,
                           n,
                           diffs=[[2, 0], [0, 2]],
                           phi=phi,
                           order=order)
# create the component for the fixed boundary conditions
A_boundary = weight_matrix(nodes[groups['boundary:all']],
                           nodes,
                           1,
                           diffs=[0, 0])
# Add the components to the corresponding rows of `A`
A = coo_matrix((N, N))
A = add_rows(A, A_interior, groups['interior'])
A = add_rows(A, A_boundary, groups['boundary:all'])

# create "right hand side" vector
d = np.zeros((N, ))
d[groups['interior']] = -1.0
Beispiel #7
0
def elastic3d_surface_force(x, nrm, p, n, lamb=1.0, mu=1.0, **kwargs):
    '''
    Returns weight matrices that map displacements at `p` to the surface
    traction force at `x` with normals `nrm` in a three-dimensional homogeneous
    elastic medium.

    Parameters
    ----------
    x: (N, 3) array
        target points which reside on a surface.

    nrm: (N, 3) array
        surface normal vectors at each point in `x`.

    p: (M, 3) array
        observation points.

    n : int
        stencil size

    lamb, mu: float
        Lame parameters

    **kwargs:
        additional arguments passed to `weight_matrix`

    Returns
    -------
    dict
        keys are the components and the values are the corresponding weight
        matrices.

    '''
    coeffs_xx = [nrm[:, 0] * (lamb + 2 * mu), nrm[:, 1] * mu, nrm[:, 2] * mu]
    diffs_xx = [(1, 0, 0), (0, 1, 0), (0, 0, 1)]
    coeffs_xy = [nrm[:, 0] * lamb, nrm[:, 1] * mu]
    diffs_xy = [(0, 1, 0), (1, 0, 0)]
    coeffs_xz = [nrm[:, 0] * lamb, nrm[:, 2] * mu]
    diffs_xz = [(0, 0, 1), (1, 0, 0)]
    coeffs_yx = [nrm[:, 0] * mu, nrm[:, 1] * lamb]
    diffs_yx = [(0, 1, 0), (1, 0, 0)]
    coeffs_yy = [nrm[:, 0] * mu, nrm[:, 1] * (lamb + 2 * mu), nrm[:, 2] * mu]
    diffs_yy = [(1, 0, 0), (0, 1, 0), (0, 0, 1)]
    coeffs_yz = [nrm[:, 1] * lamb, nrm[:, 2] * mu]
    diffs_yz = [(0, 0, 1), (0, 1, 0)]
    coeffs_zx = [nrm[:, 0] * mu, nrm[:, 2] * lamb]
    diffs_zx = [(0, 0, 1), (1, 0, 0)]
    coeffs_zy = [nrm[:, 1] * mu, nrm[:, 2] * lamb]
    diffs_zy = [(0, 0, 1), (0, 1, 0)]
    coeffs_zz = [nrm[:, 0] * mu, nrm[:, 1] * mu, nrm[:, 2] * (lamb + 2 * mu)]
    diffs_zz = [(1, 0, 0), (0, 1, 0), (0, 0, 1)]
    D_xx = weight_matrix(x, p, n, diffs_xx, coeffs=coeffs_xx, **kwargs)
    D_xy = weight_matrix(x, p, n, diffs_xy, coeffs=coeffs_xy, **kwargs)
    D_xz = weight_matrix(x, p, n, diffs_xz, coeffs=coeffs_xz, **kwargs)
    D_yx = weight_matrix(x, p, n, diffs_yx, coeffs=coeffs_yx, **kwargs)
    D_yy = weight_matrix(x, p, n, diffs_yy, coeffs=coeffs_yy, **kwargs)
    D_yz = weight_matrix(x, p, n, diffs_yz, coeffs=coeffs_yz, **kwargs)
    D_zx = weight_matrix(x, p, n, diffs_zx, coeffs=coeffs_zx, **kwargs)
    D_zy = weight_matrix(x, p, n, diffs_zy, coeffs=coeffs_zy, **kwargs)
    D_zz = weight_matrix(x, p, n, diffs_zz, coeffs=coeffs_zz, **kwargs)
    return {
        'xx': D_xx,
        'xy': D_xy,
        'xz': D_xz,
        'yx': D_yx,
        'yy': D_yy,
        'yz': D_yz,
        'zx': D_zx,
        'zy': D_zy,
        'zz': D_zz
    }
Beispiel #8
0
def elastic3d_body_force(x, p, n, lamb=1.0, mu=1.0, **kwargs):
    '''
    Returns weight matrices that map displacements at `p` to the body force at
    `x` in a three-dimensional homogeneous elastic medium.

    Parameters
    ----------
    x: (N, 3) array
        target points.

    p: (M, 3) array
        observation points.

    n : int
        stencil size

    lamb, mu: float
        first Lame parameter

    **kwargs:
        additional arguments passed to `weight_matrix`

    Returns
    -------
    dict
        keys are the components and the values are the corresponding weight
        matrices.

    '''
    coeffs_xx = [lamb + 2 * mu, mu, mu]
    diffs_xx = [(2, 0, 0), (0, 2, 0), (0, 0, 2)]
    coeffs_xy = [lamb + mu]
    diffs_xy = [(1, 1, 0)]
    coeffs_xz = [lamb + mu]
    diffs_xz = [(1, 0, 1)]
    coeffs_yx = [lamb + mu]
    diffs_yx = [(1, 1, 0)]
    coeffs_yy = [mu, lamb + 2 * mu, mu]
    diffs_yy = [(2, 0, 0), (0, 2, 0), (0, 0, 2)]
    coeffs_yz = [lamb + mu]
    diffs_yz = [(0, 1, 1)]
    coeffs_zx = [lamb + mu]
    diffs_zx = [(1, 0, 1)]
    coeffs_zy = [lamb + mu]
    diffs_zy = [(0, 1, 1)]
    coeffs_zz = [mu, mu, lamb + 2 * mu]
    diffs_zz = [(2, 0, 0), (0, 2, 0), (0, 0, 2)]
    D_xx = weight_matrix(x, p, n, diffs_xx, coeffs=coeffs_xx, **kwargs)
    D_xy = weight_matrix(x, p, n, diffs_xy, coeffs=coeffs_xy, **kwargs)
    D_xz = weight_matrix(x, p, n, diffs_xz, coeffs=coeffs_xz, **kwargs)
    D_yx = weight_matrix(x, p, n, diffs_yx, coeffs=coeffs_yx, **kwargs)
    D_yy = weight_matrix(x, p, n, diffs_yy, coeffs=coeffs_yy, **kwargs)
    D_yz = weight_matrix(x, p, n, diffs_yz, coeffs=coeffs_yz, **kwargs)
    D_zx = weight_matrix(x, p, n, diffs_zx, coeffs=coeffs_zx, **kwargs)
    D_zy = weight_matrix(x, p, n, diffs_zy, coeffs=coeffs_zy, **kwargs)
    D_zz = weight_matrix(x, p, n, diffs_zz, coeffs=coeffs_zz, **kwargs)
    return {
        'xx': D_xx,
        'xy': D_xy,
        'xz': D_xz,
        'yx': D_yx,
        'yy': D_yy,
        'yz': D_yz,
        'zx': D_zx,
        'zy': D_zy,
        'zz': D_zz
    }
Beispiel #9
0
# 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
Beispiel #10
0
                                  mu=mu,
                                  n=stencil_size,
                                  order=order,
                                  basis=basis)
D_xx = add_rows(D_xx, components['xx'], idx['boundary:all'])
D_xy = add_rows(D_xy, components['xy'], idx['boundary:all'])
D_yx = add_rows(D_xy, components['yx'], idx['boundary:all'])
D_yy = add_rows(D_yy, components['yy'], idx['boundary:all'])

# the ghost node components are left as zero

D = sp.vstack((sp.hstack((D_xx, D_xy)), sp.hstack((D_yx, D_yy)))).tocsc()

L = weight_matrix(nodes,
                  nodes,
                  diffs=[[6, 0], [0, 6]],
                  n=stencil_size,
                  basis=rbf.basis.phs7,
                  order=6)
L = sp.block_diag((L, L))
I = sp.eye(L.shape[0])
R = np.linalg.inv((I + 1e-14 * L.T.dot(L)).A)


def f(t, z):
    ''' 
  Function used for time integration. This calculates the time 
  derivative of the current state vector. 
  '''
    u, v = z.reshape((2, -1))
    dudt = v
    h = Binv.dot(u)
Beispiel #11
0
}

# 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 circle boundary nodes ghost
# nodes to improve the accuracy of the free boundary constraint.
nodes, groups, normals = poisson_disc_nodes(
    node_spacing, (vertices, simplices),
    boundary_groups=boundary_groups,
    boundary_groups_with_ghosts=['circle'])

# Create the LHS and RHS enforcing that the Lapacian is -5 at the interior
# nodes
A_interior = weight_matrix(nodes[groups['interior']],
                           nodes,
                           stencil_size, [[2, 0], [0, 2]],
                           phi=radial_basis_function,
                           order=polynomial_order)

b_interior = np.full(len(groups['interior']), -5.0)

# Enforce that the solution is x at the box boundary nodes.
A_boundary_box = weight_matrix(nodes[groups['boundary:box']],
                               nodes,
                               stencil_size, [0, 0],
                               phi=radial_basis_function,
                               order=polynomial_order)

b_boundary_box = nodes[groups['boundary:box'], 0]

# Enforce a free boundary at the circle boundary nodes.
Beispiel #12
0
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, normals = poisson_disc_nodes(
    spacing, (vert, smp),
    boundary_groups=boundary_groups,
    boundary_groups_with_ghosts=['free'])

# create the "left hand side" matrix.
# create the component which evaluates the PDE
A_interior = weight_matrix(nodes[groups['interior']],
                           nodes,
                           n,
                           diffs=[[2, 0], [0, 2]],
                           phi=phi,
                           order=order)

# use the ghost nodes to evaluate the PDE at the free boundary nodes
A_ghost = weight_matrix(nodes[groups['boundary:free']],
                        nodes,
                        n,
                        diffs=[[2, 0], [0, 2]],
                        phi=phi,
                        order=order)

# create the component for the fixed boundary conditions. This is
# essentially an identity operation and so we only need a stencil size
# of 1
A_fixed = weight_matrix(nodes[groups['boundary:fixed']],
Beispiel #13
0
from scipy.interpolate import griddata
import matplotlib.pyplot as plt

from rbf.pde.fd import weight_matrix
from rbf.pde.nodes import min_energy_nodes
from rbf.pde.geometry import contains

# define the problem domain
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]])
times = np.linspace(0.0, 2.0, 5)  # output times
N = 20000  # total number of nodes
nodes, idx, _ = min_energy_nodes(N, (vert, smp))  # generate nodes
# create differentiation matrices for the interior and boundary nodes
D = weight_matrix(nodes[idx['interior']], nodes, 50, [(2, 0), (0, 2)])
# create initial and boundary conditions
r = np.sqrt((nodes[idx['interior'], 0] - 0.5)**2 +
            (nodes[idx['interior'], 1] - 0.5)**2)
u_init = 1.0 / (1 + (r / 0.05)**4)  # initial u in the interior
dudt_init = np.zeros(len(idx['interior']))  # initial velocity in the interior
u_bnd = np.zeros(len(idx['boundary:all']))  # boundary conditions
# Make state vector containing the initial displacements and velocities
v = np.hstack([u_init, dudt_init])


def f(t, v):
    ''' 
  Function used for time integration. This calculates the time 
  derivative of the current state vector. 
  '''
Beispiel #14
0
D_xy = expand_rows(components['xy'], groups['interior+boundary:all'], n)
D_yx = expand_rows(components['yx'], groups['interior+boundary:all'], n)
D_yy = expand_rows(components['yy'], groups['interior+boundary:all'], n)

# The boundary conditions are fixed, so there is no acceleration at
# `groups['ghosts:all']`
D = sp.vstack((sp.hstack((D_xx, D_xy)),
               sp.hstack((D_yx, D_yy)))).tocsc()

# construct a matrix that maps `v` to the acceleration of `u` due to
# hyperviscosity. The boundary conditions do not change due to hyperviscosity
# nor do they influence the effect of hyperviscosity on other nodes.
H = weight_matrix(
    nodes[groups['interior+boundary:all']],
    nodes[groups['interior+boundary:all']],
    stencil_size, 
    diffs=[(4, 0), (0, 4)], 
    coeffs=[-1.0, -1.0],
    phi='phs5', 
    order=4)
H = expand_rows(H, groups['interior+boundary:all'], n)     
H = expand_cols(H, groups['interior+boundary:all'], n)     
H = sp.block_diag((H, H)).tocsc()

def state_derivative(t, z):
    u, v = z.reshape((2, -1))
    return np.hstack([v, rho*D.dot(Bsolver.solve(u)) + nu*H.dot(v)])


if plot_eigs:
    L = LinearOperator((4*n, 4*n), matvec=lambda x:state_derivative(0.0, x))
    print('computing eigenvectors')