Example #1
0
	def updateMesh(self, ctrs, fd, frame_orig, pfix = None, n_iter = 20):
		deltat = 0.1
		xmin, ymin, xmax, ymax = self.bbox
		
		if pfix is not None:
			self.p = ml.setdiff_rows(self.p, pfix)
			pfix = ml.unique_rows(pfix)
			nfix = pfix.shape[0]
		else:
			nfix = 0
	
		N = self.p.shape[0]                                   # Number of points N
		pold = float('inf')                              # For first iteration
	
		################################################################################
		#Mesh updates
		################################################################################
		
		#self.delaunay = spspatial.Delaunay(self.p)
		#self.t = self.delaunay.vertices       # List of triangles
		for ii in range(n_iter):
			dist = lambda p1, p2: np.sqrt(((p1-p2)**2).sum(1))
			if (dist(self.p, pold)/self.h0).max() > self.ttol:          # Any large movement?
				pold = self.p.copy()                          # Save current positions
				pmid = self.p[self.t].sum(1)/3                     # Compute centroids
				self.t = self.t[fd(pmid) < -self.geps]                  # Keep interior triangles
				bars = np.vstack((self.t[:, [0,1]],
									self.t[:, [1,2]],
									self.t[:, [2,0]]))          # Interior bars duplicated
				bars.sort(axis=1)
				bars = ml.unique_rows(bars)              # Bars as node pairs
	
			barvec = self.p[bars[:,0]] - self.p[bars[:,1]]         # List of bar vectors
			L = np.sqrt((barvec**2).sum(1))              # L = Bar lengths
			hbars = self.fh(self.p[bars].sum(1)/2)
			L0 = 1.4*self.h0*np.ones_like(L);
		
			#F = self.k*(L0-L)
			#F[F<0] = 0                         # Bar forces (scalars)
			F = self.F(L) 
			Fvec = F[:,None]/L[:,None].dot([[1,1]])*barvec # Bar forces (x,y components)
			Ftot = ml.dense(bars[:,[0,0,1,1]],
											np.repeat([[0,1,0,1]], len(F), axis=0),
											np.hstack((Fvec, -Fvec)),
											shape=(N, 2))
			Ftot[:nfix] = 0                              # Force = 0 at fixed points
			#self.p += self.deltat*Ftot                             # Update node positions
			self.p += deltat*Ftot                             # Update node positions
		
			d = fd(self.p); ix = d>0                          # Find points outside (d>0)
			ddeps = 1e-1
			for idx in range(10):
				if ix.any():
					dgradx = (fd(self.p[ix]+[ddeps,0])-d[ix])/ddeps # Numerical
					dgrady = (fd(self.p[ix]+[0,ddeps])-d[ix])/ddeps # gradient
					dgrad2 = dgradx**2 + dgrady**2
					self.p[ix] -= (d[ix]*np.vstack((dgradx, dgrady))/dgrad2).T # Project	

		self.bars = bars
		self.L = L 
Example #2
0
def uniref(p, t, nref=1, fd=None):
    """Uniformly refine simplicial mesh.

    Usage
    -----
    >>> p, t = uniref(p, t, nref, fd)

    Parameters
    ----------
    p : array, shape (np, dim)
        Nodes
    t : array, shape (nt, dim+1)
        Triangulation
    nref : int, optional
        Number of uniform refinements
    fd : callable as fd(p), optional
        Boundary distance function
    """

    dim = p.shape[1]
    assert dim == t.shape[1]-1

    for i in range(nref):
        n = p.shape[0]
        nt = t.shape[0]

        if dim == 1:
            pmid = (p[t[:,0]]+p[t[:,1]])/2
            t1 = t[:,[0]]
            t2 = t[:,[1]]
            t12 = arange(n, n+nt)[:,None]
            t = np.vstack((np.hstack((t1,t12)),
                           np.hstack((t12,t2))))
            p = np.vstack((p, pmid))
        elif dim == 2:
            pair = np.vstack((t[:,[0,1]],
                              t[:,[0,2]],
                              t[:,[1,2]]))
            pair.sort(1)
            pair, pairj = ml.unique_rows(pair, return_inverse=True)
            pmid = (p[pair[:,0]] + p[pair[:,1]])/2
            t1 = t[:,[0]]
            t2 = t[:,[1]]
            t3 = t[:,[2]]
            t12 = pairj[0*nt:1*nt, None] + n
            t13 = pairj[1*nt:2*nt, None] + n
            t23 = pairj[2*nt:3*nt, None] + n
            t = np.vstack((np.hstack((t1,t12,t13)),
                           np.hstack((t12,t23,t13)),
                           np.hstack((t2,t23,t12)),
                           np.hstack((t3,t13,t23))))
            p = np.vstack((p,pmid))
        else:
            raise NotImplementedError

        if fd is not None:
            for i in range(5):
                bndproj(p, t, fd)

    return p, t
Example #3
0
def boundedges(p, t):
    """Find boundary edges of a triangular mesh.

    Usage
    -----
    >>> e = boundedges(p,t)
    """
    edges = np.vstack((t[:,[0,1]],
                       t[:,[0,2]],
                       t[:,[1,2]]))
    node3 = np.hstack((t[:,2],t[:,1],t[:,0]))
    edges.sort(1)
    _, ix, jx = ml.unique_rows(edges, True, True)
    vec, _ = np.histogram(jx, np.arange(max(jx)+2))
    qx = (vec == 1).nonzero()
    e = edges[ix[qx]]
    node3 = node3[ix[qx]]

    # Orientation
    v1 = p[e[:,1]]-p[e[:,0]]
    v2 = p[node3]-p[e[:,1]]
    ix, = (v1[:,0]*v2[:,1]-v1[:,1]*v2[:,0] > 0).nonzero()
    e[ix,:] = e[ix, ::-1]

    return e
Example #4
0
def uniref(p, t, nref=1, fd=None):
    """Uniformly refine simplicial mesh.

    Usage
    -----
    >>> p, t = uniref(p, t, nref, fd)

    Parameters
    ----------
    p : array, shape (np, dim)
        Nodes
    t : array, shape (nt, dim+1)
        Triangulation
    nref : int, optional
        Number of uniform refinements
    fd : callable as fd(p), optional
        Boundary distance function
    """

    dim = p.shape[1]
    assert dim == t.shape[1] - 1

    for i in range(nref):
        n = p.shape[0]
        nt = t.shape[0]

        if dim == 1:
            pmid = (p[t[:, 0]] + p[t[:, 1]]) / 2
            t1 = t[:, [0]]
            t2 = t[:, [1]]
            t12 = arange(n, n + nt)[:, None]
            t = np.vstack((np.hstack((t1, t12)), np.hstack((t12, t2))))
            p = np.vstack((p, pmid))
        elif dim == 2:
            pair = np.vstack((t[:, [0, 1]], t[:, [0, 2]], t[:, [1, 2]]))
            pair.sort(1)
            pair, pairj = ml.unique_rows(pair, return_inverse=True)
            pmid = (p[pair[:, 0]] + p[pair[:, 1]]) / 2
            t1 = t[:, [0]]
            t2 = t[:, [1]]
            t3 = t[:, [2]]
            t12 = pairj[0 * nt:1 * nt, None] + n
            t13 = pairj[1 * nt:2 * nt, None] + n
            t23 = pairj[2 * nt:3 * nt, None] + n
            t = np.vstack((np.hstack((t1, t12, t13)), np.hstack(
                (t12, t23, t13)), np.hstack(
                    (t2, t23, t12)), np.hstack((t3, t13, t23))))
            p = np.vstack((p, pmid))
        else:
            raise NotImplementedError

        if fd is not None:
            for i in range(5):
                bndproj(p, t, fd)

    return p, t
Example #5
0
def Delaunay(p, fd=None):
    delaunay = spspatial.Delaunay(p)
    t = delaunay.vertices  # List of triangles
    pmid = p[t].sum(1) / 3  # Compute centroids
    if fd is not None:
        t = t[fd(pmid) < 0]  # Keep interior triangles
    # 4. Describe each bar by a unique pair of nodes
    bars = np.vstack(
        (t[:, [0, 1]], t[:, [1, 2]], t[:, [2, 0]]))  # Interior bars duplicated
    bars.sort(axis=1)
    bars = ml.unique_rows(bars)  # Bars as node pairs
    return bars, t
Example #6
0
def boundedgesnd(t):
    """Find boundary edges in n-dims, but no guarantees of orientation"""
    dim = t.shape[1] - 1
    vertices = set(range(dim + 1))
    faces = list(itertools.combinations(vertices, dim))

    edges = np.vstack((t[:, face] for face in faces))
    edges.sort(1)
    _, ix, jx = ml.unique_rows(edges, True, True)
    vec, _ = np.histogram(jx, np.arange(max(jx) + 2))
    qx = (vec == 1).nonzero()
    e = edges[ix[qx]]

    return e
Example #7
0
def boundedgesnd(t):
    """Find boundary edges in n-dims, but no guarantees of orientation"""
    dim = t.shape[1]-1
    vertices = set(range(dim+1))
    faces = list(itertools.combinations(vertices, dim))

    edges = np.vstack((t[:,face] for face in faces))
    edges.sort(1)
    _, ix, jx = ml.unique_rows(edges, True, True)
    vec, _ = np.histogram(jx, np.arange(max(jx)+2))
    qx = (vec == 1).nonzero()
    e = edges[ix[qx]]

    return e
Example #8
0
def mkt2t(t):
    """Compute element connectivities from element indices.

    t2t, t2n = mkt2t(t)
    """

    nt = t.shape[0]
    dim = t.shape[1]-1

    if dim == 1:
        edges = np.vstack((t[:,[1]],
                           t[:,[0]]))
    elif dim == 2:
        edges = np.vstack((t[:,[1,2]],
                           t[:,[2,0]],
                           t[:,[0,1]]))
    elif dim == 3:
        edges = np.vstack((t[:,[1,2,3]],
                           t[:,[2,3,0]],
                           t[:,[3,0,1]],
                           t[:,[0,1,2]]))
    else:
        raise NotImplementedError

    # Each row of ts is the index of the entry of t when reading the array.
    ts = np.indices(t.shape).reshape(t.ndim,-1,order='F').T

    edges.sort(1)
    _, jx = ml.unique_rows(edges, return_inverse=True)
    ix = jx.argsort()

    jx = jx[ix]
    ts = ts[ix]

    ix, = (np.diff(jx) == 0).nonzero()

    ts1 = ts[ix]
    ts2 = ts[ix+1]

    t2t = np.empty((nt, dim+1), dtype=int); t2t.fill(-1)
    t2n = np.empty((nt, dim+1), dtype=int); t2n.fill(-1)

    t2t[ts1[:,0], ts1[:,1]] = ts2[:,0]
    t2t[ts2[:,0], ts2[:,1]] = ts1[:,0]

    t2n[ts1[:,0], ts1[:,1]] = ts2[:,1]
    t2n[ts2[:,0], ts2[:,1]] = ts1[:,1]

    return t2t, t2n
Example #9
0
def mkt2t(t):
    """Compute element connectivities from element indices.

    t2t, t2n = mkt2t(t)
    """

    nt = t.shape[0]
    dim = t.shape[1] - 1

    if dim == 1:
        edges = np.vstack((t[:, [1]], t[:, [0]]))
    elif dim == 2:
        edges = np.vstack((t[:, [1, 2]], t[:, [2, 0]], t[:, [0, 1]]))
    elif dim == 3:
        edges = np.vstack(
            (t[:, [1, 2, 3]], t[:, [2, 3, 0]], t[:, [3, 0, 1]], t[:,
                                                                  [0, 1, 2]]))
    else:
        raise NotImplementedError

    # Each row of ts is the index of the entry of t when reading the array.
    ts = np.indices(t.shape).reshape(t.ndim, -1, order='F').T

    edges.sort(1)
    _, jx = ml.unique_rows(edges, return_inverse=True)
    ix = jx.argsort()

    jx = jx[ix]
    ts = ts[ix]

    ix, = (np.diff(jx) == 0).nonzero()

    ts1 = ts[ix]
    ts2 = ts[ix + 1]

    t2t = np.empty((nt, dim + 1), dtype=int)
    t2t.fill(-1)
    t2n = np.empty((nt, dim + 1), dtype=int)
    t2n.fill(-1)

    t2t[ts1[:, 0], ts1[:, 1]] = ts2[:, 0]
    t2t[ts2[:, 0], ts2[:, 1]] = ts1[:, 0]

    t2n[ts1[:, 0], ts1[:, 1]] = ts2[:, 1]
    t2n[ts2[:, 0], ts2[:, 1]] = ts1[:, 1]

    return t2t, t2n
Example #10
0
def fixmesh(p, t, ptol=2e-13):
    """Remove duplicated/unused nodes and fix element orientation.

    Parameters
    ----------
    p : array, shape (np, dim)
    t : array, shape (nt, nf)

    Usage
    -----
    p, t = fixmesh(p, t, ptol)
    """
    snap = (p.max(0) - p.min(0)).max() * ptol
    _, ix, jx = ml.unique_rows(np.round(p / snap) * snap, True, True)

    p = p[ix]
    t = jx[t]

    flip = simpvol(p, t) < 0
    t[flip, :2] = t[flip, 1::-1]

    return p, t
Example #11
0
def fixmesh(p, t, ptol=2e-13):
    """Remove duplicated/unused nodes and fix element orientation.

    Parameters
    ----------
    p : array, shape (np, dim)
    t : array, shape (nt, nf)

    Usage
    -----
    p, t = fixmesh(p, t, ptol)
    """
    snap = (p.max(0)-p.min(0)).max()*ptol
    _, ix, jx = ml.unique_rows(np.round(p/snap)*snap, True, True)

    p = p[ix]
    t = jx[t]

    flip = simpvol(p,t)<0
    t[flip, :2] = t[flip, 1::-1]

    return p, t
Example #12
0
def boundedges(p, t):
    """Find boundary edges of a triangular mesh.

    Usage
    -----
    >>> e = boundedges(p,t)
    """
    edges = np.vstack((t[:, [0, 1]], t[:, [0, 2]], t[:, [1, 2]]))
    node3 = np.hstack((t[:, 2], t[:, 1], t[:, 0]))
    edges.sort(1)
    _, ix, jx = ml.unique_rows(edges, True, True)
    vec, _ = np.histogram(jx, np.arange(max(jx) + 2))
    qx = (vec == 1).nonzero()
    e = edges[ix[qx]]
    node3 = node3[ix[qx]]

    # Orientation
    v1 = p[e[:, 1]] - p[e[:, 0]]
    v2 = p[node3] - p[e[:, 1]]
    ix, = (v1[:, 0] * v2[:, 1] - v1[:, 1] * v2[:, 0] > 0).nonzero()
    e[ix, :] = e[ix, ::-1]

    return e
Example #13
0
	def createMesh(self, ctrs, fd, frame, plot = False):
		self.frame = frame 
		pfix = None 
	
		# Extract bounding box
		xmin, ymin, xmax, ymax = self.bbox
		if pfix is not None:
			pfix = np.array(pfix, dtype='d')
		
		#1. Set up initial points 
		x, y = np.mgrid[xmin:(xmax+self.h0):self.h0,
										ymin:(ymax+self.h0*np.sqrt(3)/2):self.h0*np.sqrt(3)/2]
		x[:, 1::2] += self.h0/2                               # Shift even rows
		p = np.vstack((x.flat, y.flat)).T                # List of node coordinates
		
		# 2. Remove points outside the region, apply the rejection method
		a = fd(p)
		p = p[np.where(a<self.geps)]                          # Keep only d<0 points
		r0 = 1/self.fh(p)**2                                  # Probability to keep point
		p = p[np.random.random(p.shape[0])<r0/r0.max()]  # Rejection method
		if pfix is not None:
			p = ml.setdiff_rows(p, pfix)                 # Remove duplicated nodes
			pfix = ml.unique_rows(pfix); nfix = pfix.shape[0]
			p = np.vstack((pfix, p))                     # Prepend fix points
		else:
			nfix = 0
		N = p.shape[0]                                   # Number of points N
		self.N = N
		
		count = 0
		pold = float('inf')                              # For first iteration
		
		################################################################################
		#Mesh creation
		################################################################################
		
		while count < self.maxiter: 
			#print count 
			count += 1
			# 3. Retriangulation by the Delaunay algorithm
			dist = lambda p1, p2: np.sqrt(((p1-p2)**2).sum(1))
			if (dist(p, pold)/self.h0).max() > self.ttol:          # Any large movement?
				pold = p.copy()                          # Save current positions
				self.delaunay = spspatial.Delaunay(p)
				t = self.delaunay.vertices       # List of triangles
				pmid = p[t].sum(1)/3                     # Compute centroids
				t = t[fd(pmid) < -self.geps]                  # Keep interior triangles
				# 4. Describe each bar by a unique pair of nodes
				bars = np.vstack((t[:, [0,1]],
									t[:, [1,2]],
									t[:, [2,0]]))          # Interior bars duplicated
				bars.sort(axis=1)
				bars = ml.unique_rows(bars)              # Bars as node pairs
				#Plot
				fc = frame.copy()
				if frame is not None:
					drawGrid(fc, p, bars)
					if plot:
						cv2.imshow('Initial mesh',fc)
						k = cv2.waitKey(30) & 0xff
						if k == 27:
							break
		
			# 6. Move mesh points based on bar lengths L and forces F
			barvec = p[bars[:,0]] - p[bars[:,1]]         # List of bar vectors
			L = np.sqrt((barvec**2).sum(1))              # L = Bar lengths
			hbars = self.fh(p[bars].sum(1)/2)
			L0 = 1.5*self.h0*np.ones_like(L); #(hbars*Fscale
						#*np.sqrt((L**2).sum()/(hbars**2).sum()))  # L0 = Desired lengths
		
			F = self.k*(L0-L)
			F[F<0] = 0#F[F<0]*.5#0                         # Bar forces (scalars)
			Fvec = F[:,None]/L[:,None].dot([[1,1]])*barvec # Bar forces (x,y components)
			Ftot = ml.dense(bars[:,[0,0,1,1]],
											np.repeat([[0,1,0,1]], len(F), axis=0),
											np.hstack((Fvec, -Fvec)),
											shape=(N, 2))
			Ftot[:nfix] = 0                              # Force = 0 at fixed points
			p += self.deltat*Ftot                             # Update node positions
		
			# 7. Bring outside points back to the boundary
			d = fd(p); ix = d>0                          # Find points outside (d>0)
			ddeps = 1e-1
			for idx in range(10):
				if ix.any():
					dgradx = (fd(p[ix]+[ddeps,0])-d[ix])/ddeps # Numerical
					dgrady = (fd(p[ix]+[0,ddeps])-d[ix])/ddeps # gradient
					dgrad2 = dgradx**2 + dgrady**2
					p[ix] -= (d[ix]*np.vstack((dgradx, dgrady))/dgrad2).T # Project
		
			# 8. Termination criterion: All interior nodes move less than dptol (scaled)
			if (np.sqrt((self.deltat*Ftot[d<-self.geps]**2).sum(1))/self.h0).max() < self.dptol:
				break
		
		self.p = p 
		self.t = t 
		self.bars = bars
		self.L = L 
Example #14
0
def distmesh2d(fd,
               fh,
               h0,
               bbox,
               pfix=None,
               fig='gcf',
               dptol=.001,
               ttol=.1,
               Fscale=1.2,
               deltat=.2,
               geps_multiplier=.001,
               densityctrlfreq=30):
    """
    distmesh2d: 2-D Mesh Generator using Distance Functions.

    Usage
    -----
    >>> p, t = distmesh2d(fd, fh, h0, bbox, pfix)

    Parameters
    ----------
    fd:        Distance function d(x,y)
    fh:        Scaled edge length function h(x,y)
    h0:        Initial edge length
    bbox:      Bounding box, (xmin, ymin, xmax, ymax)
    pfix:      Fixed node positions, shape (nfix, 2)
    fig:       Figure to use for plotting, or None to disable plotting.

    Returns
    -------
    p:         Node positions (Nx2)
    t:         Triangle indices (NTx3)

    Example: (Uniform Mesh on Unit Circle)
    >>> fd = lambda p: sqrt((p**2).sum(1))-1.0
    >>> p, t = distmesh2d(fd, huniform, 2, (-1,-1,1,1))

    Example: (Rectangle with circular hole, refined at circle boundary)
    >>> fd = lambda p: ddiff(drectangle(p,-1,1,-1,1), dcircle(p,0,0,0.5))
    >>> fh = lambda p: 0.05+0.3*dcircle(p,0,0,0.5)
    >>> p, t = distmesh2d(fd, fh, 0.05, (-1,-1,1,1),
                          [(-1,-1), (-1,1), (1,-1), (1,1)])

    Example: (Polygon)
    >>> pv=[(-0.4, -0.5), (0.4, -0.2), (0.4, -0.7), (1.5, -0.4), (0.9, 0.1),
            (1.6, 0.8), (0.5, 0.5), (0.2, 1.0), (0.1, 0.4), (-0.7, 0.7),
            (-0.4, -0.5)]
    >>> fd = lambda p: dpoly(p, pv)
    >>> p, t = distmesh2d(fd, huniform, 0.1, (-1,-1, 2,1), pv)

    Example: (Ellipse)
    >>> fd = lambda p: p[:,0]**2/2**2 + p[:,1]**2/1**2 - 1
    >>> p, t = dm.distmesh2d(fd, dm.huniform, 0.2, (-2,-1, 2,1))

    Example: (Square, with size function point and line sources)
    >>> fd = lambda p: dm.drectangle(p,0,1,0,1)
    >>> fh = lambda p: np.minimum(np.minimum(
            0.01+0.3*abs(dm.dcircle(p,0,0,0)),
            0.025+0.3*abs(dm.dpoly(p,[(0.3,0.7),(0.7,0.5)]))), 0.15)
    >>> p, t = dm.distmesh2d(fd, fh, 0.01, (0,0,1,1), [(0,0),(1,0),(0,1),(1,1)])

    Example: (NACA0012 airfoil)
    >>> hlead=0.01; htrail=0.04; hmax=2; circx=2; circr=4
    >>> a=.12/.2*np.array([0.2969,-0.1260,-0.3516,0.2843,-0.1036])
    >>> a0=a[0]; a1=np.hstack((a[5:0:-1], 0.0))
    >>> fd = lambda p: dm.ddiff(
        dm.dcircle(p,circx,0,circr),
        (abs(p[:,1])-np.polyval(a1, p[:,0]))**2-a0**2*p[:,0])
    >>> fh = lambda p: np.minimum(np.minimum(
            hlead+0.3*dm.dcircle(p,0,0,0),
            htrail+0.3*dm.dcircle(p,1,0,0)), hmax)

    >>> fixx = 1.0-htrail*np.cumsum(1.3**np.arange(5))
    >>> fixy = a0*np.sqrt(fixx)+np.polyval(a1, fixx)
    >>> fix = np.vstack((
            np.array([(circx-circr,0),(circx+circr,0),
                      (circx,-circr),(circx,circr),
                      (0,0),(1,0)]),
            np.vstack((fixx, fixy)).T,
            np.vstack((fixx, -fixy)).T))
    >>> box = (circx-circr,-circr, circx+circr,circr)
    >>> h0 = min(hlead, htrail, hmax)
    >>> p, t = dm.distmesh2d(fd, fh, h0, box, fix)
    """

    if fig == 'gcf':
        import matplotlib.pyplot as plt
        fig = plt.gcf()

    geps = geps_multiplier * h0
    deps = np.sqrt(np.finfo(np.double).eps) * h0

    # Extract bounding box
    xmin, ymin, xmax, ymax = bbox
    if pfix is not None:
        pfix = np.array(pfix, dtype='d')

    # 0. Prepare a figure.
    if fig is not None:
        from distmesh.plotting import SimplexCollection
        fig.clf()
        ax = fig.gca()
        c = SimplexCollection()
        ax.add_collection(c)
        ax.set_xlim(xmin, xmax)
        ax.set_ylim(ymin, ymax)
        ax.set_aspect('equal')
        ax.set_axis_off()
        fig.canvas.draw()

    # 1. Create initial distribution in bounding box (equilateral triangles)
    x, y = np.mgrid[xmin:(xmax + h0):h0,
                    ymin:(ymax + h0 * np.sqrt(3) / 2):h0 * np.sqrt(3) / 2]
    x[:, 1::2] += h0 / 2  # Shift even rows
    p = np.vstack((x.flat, y.flat)).T  # List of node coordinates

    # 2. Remove points outside the region, apply the rejection method
    p = p[fd(p) < geps]  # Keep only d<0 points
    r0 = 1 / fh(p)**2  # Probability to keep point
    p = p[np.random.random(p.shape[0]) < r0 / r0.max()]  # Rejection method
    if pfix is not None:
        p = ml.setdiff_rows(p, pfix)  # Remove duplicated nodes
        pfix = ml.unique_rows(pfix)
        nfix = pfix.shape[0]
        p = np.vstack((pfix, p))  # Prepend fix points
    else:
        nfix = 0
    N = p.shape[0]  # Number of points N

    count = 0
    pold = float('inf')  # For first iteration

    while True:
        count += 1

        # 3. Retriangulation by the Delaunay algorithm
        dist = lambda p1, p2: np.sqrt(((p1 - p2)**2).sum(1))
        if (dist(p, pold) / h0).max() > ttol:  # Any large movement?
            pold = p.copy()  # Save current positions
            t = spspatial.Delaunay(p).vertices  # List of triangles
            pmid = p[t].sum(1) / 3  # Compute centroids
            t = t[fd(pmid) < -geps]  # Keep interior triangles
            # 4. Describe each bar by a unique pair of nodes
            bars = np.vstack((t[:, [0, 1]], t[:, [1, 2]],
                              t[:, [2, 0]]))  # Interior bars duplicated
            bars.sort(axis=1)
            bars = ml.unique_rows(bars)  # Bars as node pairs
            # 5. Graphical output of the current mesh
            if fig is not None:
                c.set_simplices((p, t))
                fig.canvas.draw()

        # 6. Move mesh points based on bar lengths L and forces F
        barvec = p[bars[:, 0]] - p[bars[:, 1]]  # List of bar vectors
        L = np.sqrt((barvec**2).sum(1))  # L = Bar lengths
        hbars = fh(p[bars].sum(1) / 2)
        L0 = (hbars * Fscale * np.sqrt(
            (L**2).sum() / (hbars**2).sum()))  # L0 = Desired lengths

        # Density control - remove points that are too close
        if (count % densityctrlfreq) == 0 and (L0 > 2 * L).any():
            ixdel = np.setdiff1d(bars[L0 > 2 * L].reshape(-1), np.arange(nfix))
            p = p[np.setdiff1d(np.arange(N), ixdel)]
            N = p.shape[0]
            pold = float('inf')
            continue

        F = L0 - L
        F[F < 0] = 0  # Bar forces (scalars)
        Fvec = F[:, None] / L[:, None].dot(
            [[1, 1]]) * barvec  # Bar forces (x,y components)
        Ftot = ml.dense(bars[:, [0, 0, 1, 1]],
                        np.repeat([[0, 1, 0, 1]], len(F), axis=0),
                        np.hstack((Fvec, -Fvec)),
                        shape=(N, 2))
        Ftot[:nfix] = 0  # Force = 0 at fixed points
        p += deltat * Ftot  # Update node positions

        # 7. Bring outside points back to the boundary
        d = fd(p)
        ix = d > 0  # Find points outside (d>0)
        if ix.any():
            dgradx = (fd(p[ix] + [deps, 0]) - d[ix]) / deps  # Numerical
            dgrady = (fd(p[ix] + [0, deps]) - d[ix]) / deps  # gradient
            dgrad2 = dgradx**2 + dgrady**2
            p[ix] -= (d[ix] * np.vstack(
                (dgradx, dgrady)) / dgrad2).T  # Project

        # 8. Termination criterion: All interior nodes move less than dptol (scaled)
        if (np.sqrt((deltat * Ftot[d < -geps]**2).sum(1)) / h0).max() < dptol:
            break

    # Clean up and plot final mesh
    p, t = dmutils.fixmesh(p, t)

    if fig is not None:
        c.set_simplices((p, t))
        fig.canvas.draw()

    return p, t
Example #15
0
    def createMesh(self, ctrs, fd, frame, plot=False):
        self.frame = frame
        pfix = None

        # Extract bounding box
        xmin, ymin, xmax, ymax = self.bbox
        if pfix is not None:
            pfix = np.array(pfix, dtype='d')

        #1. Set up initial points
        x, y = np.mgrid[xmin:(xmax + self.h0):self.h0,
                        ymin:(ymax + self.h0 * np.sqrt(3) / 2):self.h0 *
                        np.sqrt(3) / 2]
        x[:, 1::2] += self.h0 / 2  # Shift even rows
        p = np.vstack((x.flat, y.flat)).T  # List of node coordinates

        # 2. Remove points outside the region, apply the rejection method
        a = fd(p)
        p = p[np.where(a < self.geps)]  # Keep only d<0 points
        r0 = 1 / self.fh(p)**2  # Probability to keep point
        p = p[np.random.random(p.shape[0]) < r0 / r0.max()]  # Rejection method
        if pfix is not None:
            p = ml.setdiff_rows(p, pfix)  # Remove duplicated nodes
            pfix = ml.unique_rows(pfix)
            nfix = pfix.shape[0]
            p = np.vstack((pfix, p))  # Prepend fix points
        else:
            nfix = 0
        N = p.shape[0]  # Number of points N
        self.N = N

        count = 0
        pold = float('inf')  # For first iteration

        ################################################################################
        #Mesh creation
        ################################################################################

        while count < self.maxiter:
            print 'DistMesh create count: %d/%d' % (count, self.maxiter)
            count += 1
            # 3. Retriangulation by the Delaunay algorithm
            dist = lambda p1, p2: np.sqrt(((p1 - p2)**2).sum(1))
            if (dist(p, pold) /
                    self.h0).max() > self.ttol:  # Any large movement?
                pold = p.copy()  # Save current positions
                self.delaunay = spspatial.Delaunay(p)
                t = self.delaunay.vertices  # List of triangles
                pmid = p[t].sum(1) / 3  # Compute centroids
                t = t[fd(pmid) < -self.geps]  # Keep interior triangles
                # 4. Describe each bar by a unique pair of nodes
                bars = np.vstack((t[:, [0, 1]], t[:, [1, 2]],
                                  t[:, [2, 0]]))  # Interior bars duplicated
                bars.sort(axis=1)
                bars = ml.unique_rows(bars)  # Bars as node pairs
                #Plot
                fc = frame.copy()
                if frame is not None:
                    drawGrid(fc, p, bars)
                    if plot:
                        cv2.imshow('Initial mesh', fc)
                        k = cv2.waitKey(30) & 0xff
                        if k == 27:
                            break

            # 6. Move mesh points based on bar lengths L and forces F
            barvec = p[bars[:, 0]] - p[bars[:, 1]]  # List of bar vectors
            L = np.sqrt((barvec**2).sum(1))  # L = Bar lengths
            hbars = self.fh(p[bars].sum(1) / 2)
            L0 = 1.5 * self.h0 * np.ones_like(L)
            #(hbars*Fscale
            #*np.sqrt((L**2).sum()/(hbars**2).sum()))  # L0 = Desired lengths

            F = self.k * (L0 - L)
            F[F <
              0] = 0  #F[F<0]*.5#0                         # Bar forces (scalars)
            Fvec = F[:, None] / L[:, None].dot(
                [[1, 1]]) * barvec  # Bar forces (x,y components)
            Ftot = ml.dense(bars[:, [0, 0, 1, 1]],
                            np.repeat([[0, 1, 0, 1]], len(F), axis=0),
                            np.hstack((Fvec, -Fvec)),
                            shape=(N, 2))
            Ftot[:nfix] = 0  # Force = 0 at fixed points
            p += self.deltat * Ftot  # Update node positions

            # 7. Bring outside points back to the boundary
            d = fd(p)
            ix = d > 0  # Find points outside (d>0)
            ddeps = 1e-1
            for idx in range(10):
                if ix.any():
                    dgradx = (fd(p[ix] + [ddeps, 0]) -
                              d[ix]) / ddeps  # Numerical
                    dgrady = (fd(p[ix] + [0, ddeps]) -
                              d[ix]) / ddeps  # gradient
                    dgrad2 = dgradx**2 + dgrady**2
                    p[ix] -= (d[ix] * np.vstack(
                        (dgradx, dgrady)) / dgrad2).T  # Project

            # 8. Termination criterion: All interior nodes move less than dptol (scaled)
            if (np.sqrt((self.deltat * Ftot[d < -self.geps]**2).sum(1)) /
                    self.h0).max() < self.dptol:
                break

        self.p = p
        self.t = t
        self.bars = bars
        self.L = L
Example #16
0
def main():
    usage = """meshfneurons.py [vid_in] [tracks_csv] [name]

	Make animation of mesh with edges being the tracked neuron positions.
	To highlight the discontinuity in motion -- if it exists. 
		
	Ben Lansdell
	03/02/2017
	"""

    parser = argparse.ArgumentParser()
    parser.add_argument('vid_in', help='video file for animation')
    parser.add_argument('tracks_in', help='csv file with tracks')
    parser.add_argument('name', help='name to save video files')
    args = parser.parse_args()

    #Test code
    #fn_in='../hydra/video/20170202/20170202_8bit.tif'
    #mfsf_in = './mfsf_output/20170202_16bit/'
    #gridsize = 50
    #threshold = 15

    threshold = 22
    name = args.name
    if name[-1] != '/':
        name += '/'
    tracks_in = args.tracks_in
    fn_in = args.vid_in

    #Skip to this frame and create mesh
    capture = TIFFStream(fn_in, threshold)
    nx = capture.nx
    nF = capture.nframes

    #Load tracks
    ret, frame, mask = capture.read()
    (mask, ctrs, fd) = findObjectThreshold(mask, threshold=.5)

    tracks = load_tracks_csv(tracks_in)
    nC = len(tracks)
    p = np.zeros((nC, 2))
    for c in tracks.keys():
        p[c, :] = tracks[c][0][0:2]
    bars, t = Delaunay(p, fd)
    original_ori = orientation(p, t)
    nB = len(bars)

    imageoutput = name + 'mesh_neurons/'
    #Make directory if needed...
    if not os.path.exists(imageoutput):
        os.makedirs(imageoutput)

    capture = TIFFStream(fn_in, threshold)

    for idx in range(nF):

        #For each edge in each
        #Update positions based on reference positions and flow field
        print("Visualizing frame %d" % idx)
        ret, frame, mask = capture.read()
        frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)
        for c in tracks.keys():
            p[c, :] = tracks[c][idx][0:2]
        current_ori = orientation(p, t)

        invalid_ori = (current_ori * original_ori == -1)
        threeori = np.hstack((invalid_ori, invalid_ori, invalid_ori))

        bars = np.vstack(
            (t[:, [0, 1]], t[:,
                             [1, 2]], t[:,
                                        [2, 0]]))  # Interior bars duplicated

        #Bars with bad orientation...
        invalid_bars = bars[threeori, :]
        invalid_bars.sort(axis=1)
        invalid_bars = ml.unique_rows(invalid_bars)

        bars.sort(axis=1)
        bars = ml.unique_rows(bars)  # Bars as node pairs

        colors = npml.repmat([0, 255, 0], nB, 1)
        for i, b in enumerate(bars):
            if b in invalid_bars:
                colors[i] = [0, 0, 255]

        drawGrid(frame, p, bars, cols=colors)
        cv2.imwrite(imageoutput + 'frame_%03d.png' % idx, frame)

    #Make a video
    print 'Making movie'
    overlayoutput = name + 'mesh_overlay/'
    if not os.path.exists(overlayoutput):
        os.makedirs(overlayoutput)

    #avconv = 'avconv -i ' + imageoutput + 'frame_%03d.png -c:v mpeg4 -qscale 8 -y'
    avconv = 'avconv -i ' + imageoutput + 'frame_%03d.png -c:v mpeg4 -qscale 15 -y'
    os.system(avconv + ' ' + overlayoutput + 'meshneurons.mp4')
Example #17
0
def distmesh2d(fd, fh, h0, bbox, pfix=None, fig='gcf'):
    """
    distmesh2d: 2-D Mesh Generator using Distance Functions.

    Usage
    -----
    >>> p, t = distmesh2d(fd, fh, h0, bbox, pfix)

    Parameters
    ----------
    fd:        Distance function d(x,y)
    fh:        Scaled edge length function h(x,y)
    h0:        Initial edge length
    bbox:      Bounding box, (xmin, ymin, xmax, ymax)
    pfix:      Fixed node positions, shape (nfix, 2)
    fig:       Figure to use for plotting, or None to disable plotting.

    Returns
    -------
    p:         Node positions (Nx2)
    t:         Triangle indices (NTx3)

    Example: (Uniform Mesh on Unit Circle)
    >>> fd = lambda p: sqrt((p**2).sum(1))-1.0
    >>> p, t = distmesh2d(fd, huniform, 2, (-1,-1,1,1))

    Example: (Rectangle with circular hole, refined at circle boundary)
    >>> fd = lambda p: ddiff(drectangle(p,-1,1,-1,1), dcircle(p,0,0,0.5))
    >>> fh = lambda p: 0.05+0.3*dcircle(p,0,0,0.5)
    >>> p, t = distmesh2d(fd, fh, 0.05, (-1,-1,1,1),
                          [(-1,-1), (-1,1), (1,-1), (1,1)])

    Example: (Polygon)
    >>> pv=[(-0.4, -0.5), (0.4, -0.2), (0.4, -0.7), (1.5, -0.4), (0.9, 0.1),
            (1.6, 0.8), (0.5, 0.5), (0.2, 1.0), (0.1, 0.4), (-0.7, 0.7),
            (-0.4, -0.5)]
    >>> fd = lambda p: dpoly(p, pv)
    >>> p, t = distmesh2d(fd, huniform, 0.1, (-1,-1, 2,1), pv)

    Example: (Ellipse)
    >>> fd = lambda p: p[:,0]**2/2**2 + p[:,1]**2/1**2 - 1
    >>> p, t = dm.distmesh2d(fd, dm.huniform, 0.2, (-2,-1, 2,1))

    Example: (Square, with size function point and line sources)
    >>> fd = lambda p: dm.drectangle(p,0,1,0,1)
    >>> fh = lambda p: np.minimum(np.minimum(
            0.01+0.3*abs(dm.dcircle(p,0,0,0)),
            0.025+0.3*abs(dm.dpoly(p,[(0.3,0.7),(0.7,0.5)]))), 0.15)
    >>> p, t = dm.distmesh2d(fd, fh, 0.01, (0,0,1,1), [(0,0),(1,0),(0,1),(1,1)])

    Example: (NACA0012 airfoil)
    >>> hlead=0.01; htrail=0.04; hmax=2; circx=2; circr=4
    >>> a=.12/.2*np.array([0.2969,-0.1260,-0.3516,0.2843,-0.1036])
    >>> a0=a[0]; a1=np.hstack((a[5:0:-1], 0.0))
    >>> fd = lambda p: dm.ddiff(
        dm.dcircle(p,circx,0,circr),
        (abs(p[:,1])-np.polyval(a1, p[:,0]))**2-a0**2*p[:,0])
    >>> fh = lambda p: np.minimum(np.minimum(
            hlead+0.3*dm.dcircle(p,0,0,0),
            htrail+0.3*dm.dcircle(p,1,0,0)), hmax)

    >>> fixx = 1.0-htrail*np.cumsum(1.3**np.arange(5))
    >>> fixy = a0*np.sqrt(fixx)+np.polyval(a1, fixx)
    >>> fix = np.vstack((
            np.array([(circx-circr,0),(circx+circr,0),
                      (circx,-circr),(circx,circr),
                      (0,0),(1,0)]),
            np.vstack((fixx, fixy)).T,
            np.vstack((fixx, -fixy)).T))
    >>> box = (circx-circr,-circr, circx+circr,circr)
    >>> h0 = min(hlead, htrail, hmax)
    >>> p, t = dm.distmesh2d(fd, fh, h0, box, fix)
    """

    if fig == 'gcf':
        import matplotlib.pyplot as plt
        fig = plt.gcf()

    dptol=.001; ttol=.1; Fscale=1.2; deltat=.2; geps=.001*h0;
    deps=np.sqrt(np.finfo(np.double).eps)*h0;
    densityctrlfreq=30;

    # Extract bounding box
    xmin, ymin, xmax, ymax = bbox
    if pfix is not None:
        pfix = np.array(pfix, dtype='d')

    # 0. Prepare a figure.
    if fig is not None:
        from distmesh.plotting import SimplexCollection
        fig.clf()
        ax = fig.gca()
        c = SimplexCollection()
        ax.add_collection(c)
        ax.set_xlim(xmin, xmax)
        ax.set_ylim(ymin, ymax)
        ax.set_aspect('equal')
        ax.set_axis_off()
        fig.canvas.draw()

    # 1. Create initial distribution in bounding box (equilateral triangles)
    x, y = np.mgrid[xmin:(xmax+h0):h0,
                    ymin:(ymax+h0*np.sqrt(3)/2):h0*np.sqrt(3)/2]
    x[:, 1::2] += h0/2                               # Shift even rows
    p = np.vstack((x.flat, y.flat)).T                # List of node coordinates

    # 2. Remove points outside the region, apply the rejection method
    p = p[fd(p)<geps]                                # Keep only d<0 points
    r0 = 1/fh(p)**2                                  # Probability to keep point
    p = p[np.random.random(p.shape[0])<r0/r0.max()]  # Rejection method
    if pfix is not None:
        p = ml.setdiff_rows(p, pfix)                 # Remove duplicated nodes
        pfix = ml.unique_rows(pfix); nfix = pfix.shape[0]
        p = np.vstack((pfix, p))                     # Prepend fix points
    else:
        nfix = 0
    N = p.shape[0]                                   # Number of points N

    count = 0
    pold = float('inf')                              # For first iteration

    while True:
        count += 1

        # 3. Retriangulation by the Delaunay algorithm
        dist = lambda p1, p2: np.sqrt(((p1-p2)**2).sum(1))
        if (dist(p, pold)/h0).max() > ttol:          # Any large movement?
            pold = p.copy()                          # Save current positions
            t = spspatial.Delaunay(p).vertices       # List of triangles
            pmid = p[t].sum(1)/3                     # Compute centroids
            t = t[fd(pmid) < -geps]                  # Keep interior triangles
            # 4. Describe each bar by a unique pair of nodes
            bars = np.vstack((t[:, [0,1]],
                              t[:, [1,2]],
                              t[:, [2,0]]))          # Interior bars duplicated
            bars.sort(axis=1)
            bars = ml.unique_rows(bars)              # Bars as node pairs
            # 5. Graphical output of the current mesh
            if fig is not None:
                c.set_simplices((p, t))
                fig.canvas.draw()

        # 6. Move mesh points based on bar lengths L and forces F
        barvec = p[bars[:,0]] - p[bars[:,1]]         # List of bar vectors
        L = np.sqrt((barvec**2).sum(1))              # L = Bar lengths
        hbars = fh(p[bars].sum(1)/2)
        L0 = (hbars*Fscale
              *np.sqrt((L**2).sum()/(hbars**2).sum()))  # L0 = Desired lengths

        # Density control - remove points that are too close
        if (count % densityctrlfreq) == 0 and (L0 > 2*L).any():
            ixdel = np.setdiff1d(bars[L0 > 2*L].reshape(-1), np.arange(nfix))
            p = p[np.setdiff1d(np.arange(N), ixdel)]
            N = p.shape[0]; pold = float('inf')
            continue

        F = L0-L; F[F<0] = 0                         # Bar forces (scalars)
        Fvec = F[:,None]/L[:,None].dot([[1,1]])*barvec # Bar forces (x,y components)
        Ftot = ml.dense(bars[:,[0,0,1,1]],
                        np.repeat([[0,1,0,1]], len(F), axis=0),
                        np.hstack((Fvec, -Fvec)),
                        shape=(N, 2))
        Ftot[:nfix] = 0                              # Force = 0 at fixed points
        p += deltat*Ftot                             # Update node positions

        # 7. Bring outside points back to the boundary
        d = fd(p); ix = d>0                          # Find points outside (d>0)
        if ix.any():
            dgradx = (fd(p[ix]+[deps,0])-d[ix])/deps # Numerical
            dgrady = (fd(p[ix]+[0,deps])-d[ix])/deps # gradient
            dgrad2 = dgradx**2 + dgrady**2
            p[ix] -= (d[ix]*np.vstack((dgradx, dgrady))/dgrad2).T # Project

        # 8. Termination criterion: All interior nodes move less than dptol (scaled)
        if (np.sqrt((deltat*Ftot[d<-geps]**2).sum(1))/h0).max() < dptol:
            break

    # Clean up and plot final mesh
    p, t = dmutils.fixmesh(p, t)

    if fig is not None:
        c.set_simplices((p, t))
        fig.canvas.draw()

    return p, t
Example #18
0
def distmeshnd(fd, fh, h0, bbox, pfix=None, fig='gcf'):
    """
    distmeshnd: N-D Mesh Generator using Distance Functions.

    Usage
    -----
    >>> p, t = distmesh2d(fd, fh, h0, bbox, pfix)

    Parameters
    ----------
    fd:        Distance function d(x,y)
    fh:        Scaled edge length function h(x,y)
    h0:        Initial edge length
    bbox:      Bounding box, (xmin, ymin, zmin, ..., xmax, ymax, zmax, ...)
    pfix:      Fixed node positions, shape (nfix, dim)
    fig:       Figure to use for plotting, or None to disable plotting.

    Returns
    -------
    p:         Node positions (np, dim)
    t:         Triangle indices (nt, dim+1)

    Example: (Unit ball)
    >>> dim = 3
    >>> fd = lambda p: sqrt((p**2).sum(1))-1.0
    >>> bbox = np.vstack((-np.ones(dim), np.ones(dim)))
    >>> p, t = distmeshnd(fd, huniform, 2, bbox)
    """

    if fig == 'gcf':
        import matplotlib.pyplot as plt
        fig = plt.gcf()

    bbox = np.array(bbox).reshape(2, -1)
    dim = bbox.shape[1]

    ptol=.001; ttol=.1; L0mult=1+.4/2**(dim-1); deltat=.1; geps=1e-1*h0;
    deps=np.sqrt(np.finfo(np.double).eps)*h0;

    if pfix is not None:
        pfix = np.array(pfix, dtype='d')
        nfix = len(pfix)
    else:
        pfix = np.empty((0, dim))
        nfix = 0

    # 0. Prepare a figure.
    if fig is not None:
        if dim == 2:
            from distmesh.plotting import SimplexCollection
            fig.clf()
            ax = fig.gca()
            c = SimplexCollection()
            ax.add_collection(c)
            ax.set_xlim(bbox[:,0])
            ax.set_ylim(bbox[:,1])
            ax.set_aspect('equal')
            ax.set_axis_off()
            fig.canvas.draw()
        elif dim == 3:
            import mpl_toolkits.mplot3d
            from distmesh.plotting import axes_simpplot3d
            fig.clf()
            ax = fig.gca(projection='3d')
            ax.set_xlim(bbox[:,0])
            ax.set_ylim(bbox[:,1])
            ax.set_zlim(bbox[:,2])
            fig.canvas.draw()
        else:
            print("Plotting only supported in dimensions 2 and 3.")
            fig = None

    # 1. Create initial distribution in bounding box (equilateral triangles)
    p = np.mgrid[tuple(slice(min, max+h0, h0) for min, max in bbox.T)]
    p = p.reshape(dim, -1).T

    # 2. Remove points outside the region, apply the rejection method
    p = p[fd(p)<geps]                                # Keep only d<0 points
    r0 = fh(p)
    p = np.vstack((pfix,
                   p[np.random.rand(p.shape[0]) < r0.min()**dim / r0**dim]))
    N = p.shape[0]

    count = 0
    pold = float('inf')                              # For first iteration

    while True:

        # 3. Retriangulation by the Delaunay algorithm
        dist = lambda p1, p2: np.sqrt(((p1-p2)**2).sum(1))
        if (dist(p, pold)/h0).max() > ttol:          # Any large movement?
            pold = p.copy()                          # Save current positions
            t = spspatial.Delaunay(p).vertices       # List of triangles
            pmid = p[t].sum(1)/(dim+1)               # Compute centroids
            t = t[fd(pmid) < -geps]                  # Keep interior triangles
            # 4. Describe each bar by a unique pair of nodes
            bars = np.vstack((t[:,pair] for pair in
                              itertools.combinations(range(dim+1), 2)))
            bars.sort(axis=1)
            bars = ml.unique_rows(bars)              # Bars as node pairs
            # 5. Graphical output of the current mesh
            if fig is not None:
                if dim == 2:
                    c.set_simplices((p,t))
                    fig.canvas.draw()

                elif dim == 3:
                    if count % 5 == 0:
                        ax.cla()
                        axes_simpplot3d(ax, p, t, p[:,1] > 0)
                        ax.set_title('Retriangulation #%d' % count)
                        fig.canvas.draw()
            else:
                print('Retriangulation #%d' % count)
            count += 1

        # 6. Move mesh points based on bar lengths L and forces F
        barvec = p[bars[:,0]] - p[bars[:,1]]         # List of bar vectors
        L = np.sqrt((barvec**2).sum(1))              # L = Bar lengths
        hbars = fh(p[bars].sum(1)/2)
        L0 = (hbars*L0mult*((L**dim).sum()/(hbars**dim).sum())**(1.0/dim))
        F = L0-L; F[F<0] = 0                         # Bar forces (scalars)
        Fvec = F[:,None]/L[:,None].dot(np.ones((1,dim)))*barvec # Bar forces (x,y components)
        Ftot = ml.dense(bars[:,[0]*dim+[1]*dim],
                        np.repeat([list(range(dim))*2], len(F), axis=0),
                        np.hstack((Fvec, -Fvec)),
                        shape=(N, dim))
        Ftot[:nfix] = 0                              # Force = 0 at fixed points
        p += deltat*Ftot                             # Update node positions

        # 7. Bring outside points back to the boundary
        d = fd(p); ix = d>0                          # Find points outside (d>0)
        if ix.any():
            def deps_vec(i): a = [0]*dim; a[i] = deps; return a
            dgrads = [(fd(p[ix]+deps_vec(i))-d[ix])/deps for i in range(dim)]
            dgrad2 = sum(dgrad**2 for dgrad in dgrads)
            p[ix] -= (d[ix]*np.vstack(dgrads)/dgrad2).T # Project

        # 8. Termination criterion: All interior nodes move less than dptol (scaled)
        maxdp = deltat*np.sqrt((Ftot[d<-geps]**2).sum(1)).max()
        if maxdp < ptol*h0:
            break

    return p, t
Example #19
0
    def updateMesh(self, ctrs, fd, frame_orig, pfix=None, n_iter=20):
        deltat = 0.1
        xmin, ymin, xmax, ymax = self.bbox

        if pfix is not None:
            self.p = ml.setdiff_rows(self.p, pfix)
            pfix = ml.unique_rows(pfix)
            nfix = pfix.shape[0]
        else:
            nfix = 0

        N = self.p.shape[0]  # Number of points N
        pold = float('inf')  # For first iteration

        ################################################################################
        #Mesh updates
        ################################################################################

        #self.delaunay = spspatial.Delaunay(self.p)
        #self.t = self.delaunay.vertices       # List of triangles
        for ii in range(n_iter):
            dist = lambda p1, p2: np.sqrt(((p1 - p2)**2).sum(1))
            if (dist(self.p, pold) /
                    self.h0).max() > self.ttol:  # Any large movement?
                pold = self.p.copy()  # Save current positions
                pmid = self.p[self.t].sum(1) / 3  # Compute centroids
                self.t = self.t[fd(pmid) <
                                -self.geps]  # Keep interior triangles
                bars = np.vstack((self.t[:, [0, 1]], self.t[:, [1, 2]],
                                  self.t[:,
                                         [2, 0]]))  # Interior bars duplicated
                bars.sort(axis=1)
                bars = ml.unique_rows(bars)  # Bars as node pairs

            barvec = self.p[bars[:,
                                 0]] - self.p[bars[:,
                                                   1]]  # List of bar vectors
            L = np.sqrt((barvec**2).sum(1))  # L = Bar lengths
            hbars = self.fh(self.p[bars].sum(1) / 2)
            L0 = 1.4 * self.h0 * np.ones_like(L)

            #F = self.k*(L0-L)
            #F[F<0] = 0                         # Bar forces (scalars)
            F = self.F(L)
            Fvec = F[:, None] / L[:, None].dot(
                [[1, 1]]) * barvec  # Bar forces (x,y components)
            Ftot = ml.dense(bars[:, [0, 0, 1, 1]],
                            np.repeat([[0, 1, 0, 1]], len(F), axis=0),
                            np.hstack((Fvec, -Fvec)),
                            shape=(N, 2))
            Ftot[:nfix] = 0  # Force = 0 at fixed points
            #self.p += self.deltat*Ftot                             # Update node positions
            self.p += deltat * Ftot  # Update node positions

            d = fd(self.p)
            ix = d > 0  # Find points outside (d>0)
            ddeps = 1e-1
            for idx in range(10):
                if ix.any():
                    dgradx = (fd(self.p[ix] + [ddeps, 0]) -
                              d[ix]) / ddeps  # Numerical
                    dgrady = (fd(self.p[ix] + [0, ddeps]) -
                              d[ix]) / ddeps  # gradient
                    dgrad2 = dgradx**2 + dgrady**2
                    self.p[ix] -= (d[ix] * np.vstack(
                        (dgradx, dgrady)) / dgrad2).T  # Project

        self.bars = bars
        self.L = L