Beispiel #1
0
def _vertex_outward_normals(vert, smp):
    '''
  Get the "normal" vectors for each vertex of the domain. Here the
  normal vector is the average of the normal vectors for each simplex
  that the vertex is part of.
  '''
    simplex_normals = simplex_outward_normals(vert, smp)
    vertex_normals = np.zeros_like(vert)
    for i, s in enumerate(smp):
        vertex_normals[s] += simplex_normals[i]

    vertex_normals /= np.linalg.norm(vertex_normals, axis=1)[:, None]
    return vertex_normals
Beispiel #2
0
def _make_normal_vectors(smpid, vert, smp):
    '''
  Create an (n, d) array of normal vectors for each node. If the node
  is not a boundary node then the corresponding row contains NaN's.
  '''
    # get the normal vectors for each simplex
    simplex_normals = simplex_outward_normals(vert, smp)
    # allocate an array of nans for the node normal vectors
    normals = np.full((smpid.shape[0], vert.shape[1]), np.nan)
    # find which nodes are attached to a simplex. set those normal
    # vectors to be the normal vector for the simplex they are attached
    # to
    normals[smpid >= 0] = simplex_normals[smpid[smpid >= 0]]
    return normals
Beispiel #3
0
def make_ghost_nodes(nodes,smpid,idx,vert,smp):
  # create nodes that are just outside the boundary
  nodes = np.asarray(nodes)
  smpid = np.asarray(smpid)
  sub_nodes = nodes[idx]
  sub_smpid = smpid[idx]
  if np.any(sub_smpid == -1):
    raise ValueError('cannot make a ghost node for an interior node')
    
  norms = simplex_outward_normals(vert,smp)[sub_smpid]
  dummy,dx = rbf.stencil.nearest(sub_nodes,nodes,2,vert=vert,smp=smp)
  # distance to the nearest neighbors
  dx = dx[:,[1]]
  ghosts = sub_nodes + dx*norms   
  return ghosts
Beispiel #4
0
def make_ghost_nodes(nodes, smpid, idx, vert, smp):
    # create nodes that are just outside the boundary
    nodes = np.asarray(nodes)
    smpid = np.asarray(smpid)
    sub_nodes = nodes[idx]
    sub_smpid = smpid[idx]
    if np.any(sub_smpid == -1):
        raise ValueError('cannot make a ghost node for an interior node')

    norms = simplex_outward_normals(vert, smp)[sub_smpid]
    dummy, dx = rbf.stencil.nearest(sub_nodes, nodes, 2, vert=vert, smp=smp)
    # distance to the nearest neighbors
    dx = dx[:, [1]]
    ghosts = sub_nodes + dx * norms
    return ghosts
Beispiel #5
0
  out1 = np.empty_like(n,dtype=float)
  out1[:,0] = -np.sum(n,axis=1) + n[:,0]
  out1[:,1:] = n[:,[0]] 
  out1 /= np.linalg.norm(out1,axis=1)[:,None] # normalize length
  out2 = np.cross(n,out1) # find vectors that are orthogonal to *n* and *out1*
  out2 /= np.linalg.norm(out2,axis=1)[:,None] # normalize length
  return out1,out2

# generate nodes. Note that this may take a while
nodes,smpid = menodes(N,vert,smp,rho=density_func,itr=50)
# find which nodes are attached to each simplex
int_idx = np.nonzero(smpid == -1)[0].tolist()
roller_idx = np.nonzero((smpid >= 0) & (smpid <= 9))[0].tolist()
free_idx = np.nonzero(smpid > 9)[0].tolist()
# find normal vectors to each free surface node
simplex_normals = simplex_outward_normals(vert,smp)
free_normals = simplex_normals[smpid[free_idx]]
# find the normal vectors to each roller node
roller_normals = simplex_normals[smpid[roller_idx]]
# find two orthogonal vectors that are parallel to the surface at each 
# roller node. This is used to determine the directions along which 
# traction forces will be constrained. Note that any two orthogonal 
# vectors that are parallel to the surface would do.
roller_parallels1,roller_parallels2 = find_orthogonals(roller_normals)
# add ghost nodes next to free and roller nodes
dx = np.min(neighbors(nodes,2)[1][:,1])
nodes = np.vstack((nodes,nodes[free_idx] + dx*free_normals))
nodes = np.vstack((nodes,nodes[roller_idx] + dx*roller_normals))
# build the "left hand side" matrices for body force constraints
A_body = elastic3d_body_force(nodes[int_idx+free_idx+roller_idx],nodes,lamb=lamb,mu=mu,n=n)
A_body_x,A_body_y,A_body_z = (hstack(i) for i in A_body)
Beispiel #6
0
import matplotlib.pyplot as plt
from scipy.integrate import ode
from scipy.interpolate import griddata
from scipy.sparse.linalg import spsolve

# 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 = 50000  # total number of nodes
nodes, smpid = menodes(N, vert, smp)  # generate nodes
interior = np.nonzero(smpid == -1)[0].tolist()  # identify boundary nodes
boundary = np.nonzero(smpid >= 0)[0].tolist()  # identify boundary nodes
# calculate surface normal vector for each boundary node
normals = simplex_outward_normals(vert, smp)[smpid[boundary]]
# dx is the shortest distance between any two nodes
dx = np.min(neighbors(nodes, 2)[1][:, 1])
# add ghost nodes to greatly improve accuracy at the free surface
nodes = np.vstack((nodes, nodes[boundary] + 0.5 * dx * normals))
ghost = range(N, N + len(boundary))  # ghost node indices
# create differentiation matrices for the interior and boundary nodes
D = weight_matrix(nodes[interior + boundary], nodes, [(2, 0), (0, 2)], n=30)
dD = weight_matrix(nodes[boundary],
                   nodes, [(1, 0), (0, 1)],
                   coeffs=normals.T,
                   n=30)
# create initial and boundary conditions
r = np.sqrt((nodes[interior + boundary, 0] - 0.5)**2 +
            (nodes[interior + boundary, 1] - 0.5)**2)
u_init = 1.0 / (1 + (r / 0.05)**4)  # initial u in the interior
Beispiel #7
0
bnd_vert = np.array([[0.0,0.0],[5.0,0.0]])
bnd_smp = np.array([[0,1]])

weight_kwargs = {'vert':bnd_vert,'smp':bnd_smp,'n':20,'order':2}

# build lhs
# enforce laplacian on interior nodes
A_interior = weight_matrix(nodes[interior],nodes,
                           [[2,0],[0,2]],
                           **weight_kwargs)
A_ghost = weight_matrix(nodes[boundary],nodes,
                        [[2,0],[0,2]],
                        **weight_kwargs)

# find boundary normal vectors
normals = simplex_outward_normals(vert,smp)[smpid[boundary]]
n1 = scipy.sparse.diags(normals[:,0],0)
n2 = scipy.sparse.diags(normals[:,1],0)
# enforce free surface boundary conditions
A_boundary = (n1*weight_matrix(nodes[boundary],nodes,[1,0],**weight_kwargs) +
              n2*weight_matrix(nodes[boundary],nodes,[0,1],**weight_kwargs))

# These next two matrices are really just identity matrices padded with zeros
A_slit_top = weight_matrix(nodes[slit_top],nodes,[0,0],**weight_kwargs)
A_slit_bot = weight_matrix(nodes[slit_bot],nodes,[0,0],**weight_kwargs)

A = scipy.sparse.vstack((A_interior,A_ghost,A_boundary,
                         A_slit_top,A_slit_bot))

# build the rhs in the same order
d_interior = np.zeros(interior.shape[0])