├── .gitignore
├── test.jpg
├── run.sh
├── data
├── cell_indices.txt
├── network_vertices.txt
└── edges.txt
├── parameters.py
├── parser.py
├── relax.py
├── energy.py
├── README.md
├── Polygon.py
├── MD.py
├── plot.py
├── steepest_descent.py
├── geometry.py
├── force.py
└── transition.py
/.gitignore:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alsignoriello/active_vertex_model/HEAD/test.jpg
--------------------------------------------------------------------------------
/run.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/bash
2 |
3 | vertex_file=$1
4 | edge_file=$2
5 | poly_file=$3
6 | folder=$4
7 | eta=$5
8 |
9 |
10 | # Relaxation (steepest descent)
11 | # python relax.py $vertex_file $edge_file $poly_file
12 | # python plot.py $vertex_file $edge_file $poly_file
13 |
14 |
15 | # Molecular Dynamics
16 | python MD.py $vertex_file $edge_file $poly_file $folder $eta
17 |
18 | # later, will add division simulations..
19 | # python divide.py $vertex_file $edge_file $poly_file
20 |
21 |
--------------------------------------------------------------------------------
/data/cell_indices.txt:
--------------------------------------------------------------------------------
1 | 0 1 41 40 47 7
2 | 0 7 6 14 15 8
3 | 0 8 9 10 2 1
4 | 1 2 3 43 42 41
5 | 2 10 11 12 4 3
6 | 3 4 5 45 44 43
7 | 4 12 13 14 6 5
8 | 5 6 7 47 46 45
9 | 8 15 23 16 17 9
10 | 9 17 18 19 11 10
11 | 11 19 20 21 13 12
12 | 13 21 22 23 15 14
13 | 16 23 22 30 31 24
14 | 16 24 25 26 18 17
15 | 18 26 27 28 20 19
16 | 20 28 29 30 22 21
17 | 24 31 39 32 33 25
18 | 25 33 34 35 27 26
19 | 27 35 36 37 29 28
20 | 29 37 38 39 31 30
21 | 32 39 38 46 47 40
22 | 32 40 41 42 34 33
23 | 34 42 43 44 36 35
24 | 36 44 45 46 38 37
--------------------------------------------------------------------------------
/parameters.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | """
4 |
5 | Builds a parameter dictionary
6 |
7 | """
8 |
9 | def get_parameters(lx, ly, ka, gamma, Lambda, eta, xi, lmin, delta_t):
10 |
11 | parameters = {}
12 |
13 | # Side length of box in x direction
14 | parameters['lx'] = lx
15 |
16 | # Side length of box in y directions
17 | parameters['ly'] = ly
18 |
19 | # ka - elastic area coefficient
20 | parameters['ka'] = ka
21 |
22 | # gamma - actin myosin contraction coefficient
23 | parameters['gamma'] = gamma
24 |
25 | # lambda - line tension coefficient
26 | parameters['Lambda'] = Lambda
27 |
28 | # eta - noise scaling coefficient
29 | parameters['eta'] = eta
30 |
31 | # xi - motility coefficient
32 | parameters['xi'] = xi
33 |
34 | # lmin - minimum bond length between two vertices
35 | parameters['lmin'] = lmin
36 |
37 | # delta t - time step
38 | parameters['delta_t'] = delta_t
39 |
40 |
41 | return parameters
--------------------------------------------------------------------------------
/data/network_vertices.txt:
--------------------------------------------------------------------------------
1 | 0.930866 0.271744
2 | 0.116862 0.802272
3 | 0.563237 1.233827
4 | 0.349978 1.817110
5 | 0.375702 2.313142
6 | 0.604067 2.999615
7 | 0.299085 3.474244
8 | -0.064818 4.652581
9 | 1.398975 -0.074888
10 | 1.391676 1.049655
11 | 1.160173 1.564420
12 | 1.608240 1.961066
13 | 1.342551 2.416602
14 | 1.562803 3.106261
15 | 1.064323 3.488212
16 | 1.391571 3.776807
17 | 2.141749 0.281557
18 | 2.448764 1.049310
19 | 2.586193 1.480577
20 | 2.184154 1.890135
21 | 2.543788 2.569701
22 | 1.866666 2.730649
23 | 2.487271 3.514713
24 | 1.770058 3.801211
25 | 3.063610 0.284279
26 | 3.555957 0.889567
27 | 2.773178 1.238788
28 | 3.222748 1.948208
29 | 3.511009 2.742986
30 | 3.469543 2.862983
31 | 3.386142 3.557367
32 | 3.241826 4.298552
33 | 4.185830 0.387196
34 | 4.197804 0.781788
35 | 3.907473 1.217865
36 | 4.145059 2.032152
37 | 4.437937 2.698011
38 | 3.992574 3.148598
39 | 4.143524 3.371457
40 | 4.134823 4.588720
41 | 4.703293 0.511607
42 | 5.243425 0.469836
43 | 5.109806 1.133103
44 | 5.229939 1.648571
45 | 4.891341 2.325022
46 | 5.372004 3.201157
47 | 5.047313 3.488913
48 | 4.917538 4.471589
--------------------------------------------------------------------------------
/parser.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | import numpy as np
3 | from Polygon import Polygon
4 | from geometry import rand_angle
5 |
6 | """
7 |
8 | parser.py - defines functions to read and write relevant data
9 |
10 |
11 | author: Lexi Signoriello
12 | date: 1/22/16
13 |
14 |
15 |
16 | """
17 |
18 |
19 | def read_poly_indices(file):
20 | # indices = np.loadtxt(file, dtype=int)
21 | indices = []
22 | f = open(file)
23 | for line in f:
24 | poly_indices = []
25 | linesplit = line.strip().split("\t")
26 | for i in linesplit:
27 | poly_indices.append(int(i))
28 | indices.append(poly_indices)
29 | f.close()
30 | return indices
31 |
32 |
33 | def build_polygons(cell_indices, A0):
34 | polys = []
35 | for i,indices in enumerate(cell_indices):
36 | theta = rand_angle()
37 | poly = Polygon(i, indices, A0, theta)
38 | polys.append(poly)
39 | return polys
40 |
41 |
42 | def read_vertices(file):
43 | vertices = np.loadtxt(file)
44 | return vertices
45 |
46 | def write_vertices(vertices, file):
47 | np.savetxt(file, vertices)
48 | return
49 |
50 | # i1 i2
51 | # indices for edge from v1 to v2
52 | def read_edges(file):
53 | edges = np.loadtxt(file).astype(int)
54 | return edges
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/relax.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | import sys
3 | from parameters import get_parameters
4 | from steepest_descent import steepest_descent
5 | from parser import *
6 |
7 | """
8 |
9 | Relaxes current network using a steepest descent method
10 |
11 |
12 | """
13 |
14 | # command line arguments for data files
15 | vertex_file = sys.argv[1]
16 | edge_file = sys.argv[2]
17 | poly_file = sys.argv[3]
18 |
19 |
20 | # Parameters
21 | lx = 9 * (2 / (3 * (3**0.5)))**0.5
22 | ly = 4 * (2 / (3**0.5))**0.5
23 | ka = 1.
24 | A0 = 1. # current preferred area for polygon
25 | gamma = 0.04 * ka * A0 # hexagonal network
26 | # gamma = 0.1 * ka * A0 # soft network
27 | Lambda = 0.12 * ka * (A0**(3/2)) # hexagonal network
28 | # Lambda = -0.85 * ka * A0**(3/2) # soft network
29 | lmin = 0.2
30 | delta_t = 0.05
31 | eta = 1.
32 |
33 |
34 | # get parameter dictionary
35 | parameters = get_parameters(lx, ly, ka, gamma, Lambda, eta, lmin, delta_t)
36 |
37 | # get vertices
38 | vertices = read_vertices(vertex_file)
39 |
40 | # get edges
41 | edges = read_edges(edge_file)
42 |
43 | # get polygons
44 | poly_indices = read_poly_indices(poly_file)
45 | polys = build_polygons(poly_indices, A0)
46 |
47 | steepest_descent(vertices, edges, polys, parameters)
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/data/edges.txt:
--------------------------------------------------------------------------------
1 | 0 7
2 | 0 1
3 | 0 8
4 | 1 0
5 | 1 41
6 | 1 2
7 | 2 1
8 | 2 3
9 | 2 10
10 | 3 2
11 | 3 43
12 | 3 4
13 | 4 3
14 | 4 5
15 | 4 12
16 | 5 4
17 | 5 45
18 | 5 6
19 | 6 5
20 | 6 7
21 | 6 14
22 | 7 6
23 | 7 47
24 | 7 0
25 | 8 15
26 | 8 0
27 | 8 9
28 | 9 8
29 | 9 10
30 | 9 17
31 | 10 9
32 | 10 2
33 | 10 11
34 | 11 10
35 | 11 12
36 | 11 19
37 | 12 11
38 | 12 4
39 | 12 13
40 | 13 12
41 | 13 14
42 | 13 21
43 | 14 13
44 | 14 6
45 | 14 15
46 | 15 14
47 | 15 8
48 | 15 23
49 | 16 23
50 | 16 17
51 | 16 24
52 | 17 16
53 | 17 9
54 | 17 18
55 | 18 17
56 | 18 19
57 | 18 26
58 | 19 18
59 | 19 11
60 | 19 20
61 | 20 19
62 | 20 21
63 | 20 28
64 | 21 20
65 | 21 13
66 | 21 22
67 | 22 21
68 | 22 23
69 | 22 30
70 | 23 22
71 | 23 15
72 | 23 16
73 | 24 31
74 | 24 16
75 | 24 25
76 | 25 24
77 | 25 26
78 | 25 33
79 | 26 25
80 | 26 18
81 | 26 27
82 | 27 26
83 | 27 28
84 | 27 35
85 | 28 27
86 | 28 20
87 | 28 29
88 | 29 28
89 | 29 30
90 | 29 37
91 | 30 29
92 | 30 22
93 | 30 31
94 | 31 30
95 | 31 24
96 | 31 39
97 | 32 39
98 | 32 33
99 | 32 40
100 | 33 32
101 | 33 25
102 | 33 34
103 | 34 33
104 | 34 35
105 | 34 42
106 | 35 34
107 | 35 27
108 | 35 36
109 | 36 35
110 | 36 37
111 | 36 44
112 | 37 36
113 | 37 29
114 | 37 38
115 | 38 37
116 | 38 39
117 | 38 46
118 | 39 38
119 | 39 31
120 | 39 32
121 | 40 47
122 | 40 32
123 | 40 41
124 | 41 40
125 | 41 42
126 | 41 1
127 | 42 41
128 | 42 34
129 | 42 43
130 | 43 42
131 | 43 44
132 | 43 3
133 | 44 43
134 | 44 36
135 | 44 45
136 | 45 44
137 | 45 46
138 | 45 5
139 | 46 45
140 | 46 38
141 | 46 47
142 | 47 46
143 | 47 40
144 | 47 7
--------------------------------------------------------------------------------
/energy.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | import numpy as np
3 | from Polygon import Polygon
4 | from geometry import periodic_diff, euclidean_distance
5 |
6 | """
7 |
8 | energy.py - contains components to compute the potential energy
9 | in the current configuration of vertex model
10 |
11 |
12 | author: Lexi Signoriello
13 | date: 1/20/16
14 |
15 |
16 |
17 | """
18 |
19 |
20 | def get_energy(vertices, polys, edges, parameters):
21 | # get necessary parameters
22 | lx = parameters['lx']
23 | ly = parameters['ly']
24 | L = np.array([lx,ly])
25 | ka = parameters['ka']
26 | Lambda = parameters['Lambda']
27 | gamma = parameters['gamma']
28 |
29 | e1 = E_elasticity(vertices, polys, ka, L)
30 | e2 = E_adhesion(vertices, edges, Lambda, L)
31 | # take into account double counting edges
32 | e2 = e2 / 4.
33 |
34 | e3 = E_contraction(vertices, polys, gamma, L)
35 |
36 | return (e1 + e2 + e3)
37 |
38 |
39 |
40 | def E_elasticity(vertices, polys, ka, L):
41 | e = 0.
42 | for poly in polys:
43 | a = poly.get_area(vertices, L)
44 | A0 = poly.A0
45 | e += (ka / 2.) * (a - A0)**2
46 | return e
47 |
48 |
49 |
50 | def E_adhesion(vertices, edges, Lambda , L):
51 | e = 0.
52 | for edge in edges:
53 | i1 = edge[0]
54 | i2 = edge[1]
55 | v1 = vertices[i1]
56 | vertex2 = vertices[i2]
57 | v2 = v1 + periodic_diff(vertex2, v1, L)
58 | dist = euclidean_distance(v1[0], v1[1], v2[0], v2[1])
59 | e += Lambda * dist
60 | return e
61 |
62 |
63 | def E_contraction(vertices, polys, gamma, L):
64 | e = 0.
65 | for poly in polys:
66 | p = poly.get_perim(vertices, L)
67 | e += ((gamma / 2.) * (p**2))
68 | return e
69 |
70 |
71 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Vertex Model
2 |
3 | The vertex model uses polygons, composed of vertices and edges, to illustrate the mechanics in formation of polygon sheets. This model has successfully been applied to fly wings and eyes in 2D.
4 |
5 | Simulations compute the energy and forces in the system using the following equations:
6 |
7 | E = 0.5 Σα Kα (A α - Aα)2 + Σ i,j Λi,j l i,j + 0.5 Σ α Γα Pα2
8 |
9 | where A is the area and P is the perimeter.
10 |
11 | ⃗Fi = - ⃗∇ iEi
12 |
13 |
14 | The terms represent cell elasticity, line tension and contraction, respectively.
15 |
16 |
17 |
18 |
19 | Farhadifar, R., Röper, J.-C., Aigouy, B., Eaton, S. & Jülicher, F. The Influence of Cell Mechanics, Cell-Cell Interactions, and Proliferation on Epithelial Packing. Current Biology 17, 2095–2104 (2007).
20 |
21 |
22 | # Parameters
23 |
24 |
25 | |Parameter | Definition | Range |
26 | |----------|------------|-------|
27 | | lx | length of box x-axis | positive float |
28 | | ly | length of box y-axis | positive float |
29 | | kA | elasticity | |
30 | | Λ | line tension | |
31 | | Γ | contraction| |
32 | | lmin | minimum bond length | positive float |
33 | | Δ t| time step | small positive float |
34 |
35 | # Input
36 |
37 | vertices.txt (x,y) coordinates for every vertex in network
38 |
39 | edges.txt (index1, index2) indices for every edge between two vertices in the network
40 |
41 | cells.txt (index0, index1, ... indexN) indices in counter-clockwise order that form every cell in the network, a cell is defined as a polygon, does not assume number of sides
42 |
43 |
44 | # Notes
45 |
46 | - Periodic boundary conditions
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/Polygon.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | import numpy as np
3 | from geometry import *
4 |
5 | """
6 |
7 | Polygon.py - Class Polygon to define unique characteristics
8 | of every polygons in the network
9 |
10 | author: Lexi Signoriello
11 | date: 1/19/16
12 |
13 | vertices - list of all vertices in the network
14 | [(x0,y0), (x1,y1) .... (xNvertices,yNvertices)]
15 |
16 | indices - list of indices mapping to vertices
17 | for every vertex in current poly
18 | * counter-clockwise order
19 | * list of integers
20 |
21 | n_sides - number of sides in polygon for given cell
22 |
23 | L - length of box
24 | * used to compute periodic boundary conditions
25 |
26 | """
27 |
28 |
29 |
30 | class Polygon:
31 |
32 |
33 | def __init__(self, id, indices, A0, theta):
34 | self.id = id
35 | self.indices = indices
36 | self.A0 = A0
37 | self.theta = theta
38 |
39 | # return list of vertices
40 | # with periodic boundaries
41 | def get_poly_vertices(self, vertices, L):
42 | indices = self.indices
43 | nsides = len(indices)
44 |
45 | # array of x,y vertices in counter-clockwise order
46 | # moving vertices to maintain periodic boundaries
47 | poly_vertices = []
48 |
49 | # align everything to previous vertex
50 | x0,y0 = vertices[indices[0]]
51 | v0 = np.array((x0,y0))
52 | v_last = v0
53 |
54 | for i in indices:
55 | x,y = vertices[i]
56 | v = np.array((x,y))
57 | v_next = v_last + periodic_diff(v, v_last, L)
58 | x,y = v_next
59 | poly_vertices.append((x,y))
60 | v_last = np.array((x,y))
61 | return poly_vertices
62 |
63 | def get_area(self, vertices, L):
64 | poly_vertices = self.get_poly_vertices(vertices, L)
65 | a = area(poly_vertices)
66 | return a
67 |
68 | def get_perim(self, vertices, L):
69 | poly_vertices = self.get_poly_vertices(vertices, L)
70 | p = perimeter(poly_vertices)
71 | return p
72 |
73 | def get_center(self, vertices, L):
74 | x,y = center(self.get_poly_vertices(vertices, L))
75 | return x,y
76 |
77 | def set_indices(self, indices):
78 | self.indices = indices
79 |
80 |
--------------------------------------------------------------------------------
/MD.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | import numpy as np
3 | from energy import get_energy
4 | from force import get_forces, move_vertices
5 | from transition import T1_transition
6 | import sys
7 | from parameters import get_parameters
8 | from parser import *
9 | from plot import plot_network
10 |
11 |
12 | def molecular_dynamics(vertices, edges, polys, parameters, T, folder):
13 |
14 | delta_t = parameters['delta_t']
15 | lx = parameters['lx']
16 | ly = parameters['ly']
17 | L = np.array([lx,ly])
18 |
19 | # time
20 | t = 0
21 | count = 0
22 |
23 | while t < T:
24 |
25 | # get energy for network
26 | energy = get_energy(vertices, polys, edges, parameters)
27 | # print energy
28 |
29 | # get forces for network
30 | forces = get_forces(vertices, polys, edges, parameters)
31 | print t, np.sum(forces**2)**(0.5)
32 |
33 | # move vertices
34 | vertices = move_vertices(vertices, forces, parameters)
35 |
36 | # check for T1 transitions
37 | polys, edges = T1_transition(vertices, polys, edges, parameters)
38 |
39 | # add routine to write vertices, energy, forces at every time step
40 | # can be used for plotting routines later...
41 | # write_vertices(vertices, "%s/%.2f.txt" % (folder,t))
42 | # write edges?
43 | # write polygons?
44 | # if count % 21 == 0:
45 | plot_network(vertices, polys, L, "%s/%.2f.jpg" % (folder,t))
46 |
47 | count += 1
48 | t += delta_t
49 |
50 | return
51 |
52 |
53 |
54 | # command line arguments for data files
55 | vertex_file = sys.argv[1]
56 | edge_file = sys.argv[2]
57 | poly_file = sys.argv[3]
58 | folder = sys.argv[4]
59 | eta = float(sys.argv[5])
60 |
61 |
62 | # Parameters
63 | # lx = 9 * (2 / (3 * (3**0.5)))**0.5
64 | # ly = 4 * (2 / (3**0.5))**0.5
65 | L = np.loadtxt("%s/L" % "data")
66 | lx = L[0]
67 | ly = L[1]
68 |
69 |
70 | ka = 1.
71 | A0 = 1. # current preferred area for polygon
72 | gamma = 0.04 * ka * A0 # hexagonal network
73 | # gamma = 0.1 * ka * A0 # soft network
74 | Lambda = 0.12 * ka * (A0**(3/2)) # hexagonal network
75 | # Lambda = -0.85 * ka * A0**(3/2) # soft network
76 | lmin = 0.2
77 | delta_t = 0.05
78 | # eta = 0.01
79 | xi = 0.2
80 |
81 | # maximum Time
82 | T = 5.
83 |
84 | # get parameter dictionary
85 | parameters = get_parameters(lx, ly, ka, gamma, Lambda, eta, xi, lmin, delta_t)
86 |
87 | # get vertices
88 | vertices = read_vertices(vertex_file)
89 |
90 | # get edges
91 | edges = read_edges(edge_file)
92 |
93 | # get polygons
94 | poly_indices = read_poly_indices(poly_file)
95 | polys = build_polygons(poly_indices, A0)
96 |
97 | molecular_dynamics(vertices, edges, polys, parameters, T, folder)
--------------------------------------------------------------------------------
/plot.py:
--------------------------------------------------------------------------------
1 | import matplotlib.pyplot as plt
2 | import sys
3 | from parser import *
4 | from geometry import periodic_diff
5 |
6 | """
7 |
8 | plot.py - plots the network for vertex model
9 |
10 |
11 | author: Lexi Signoriello
12 | date: 1/19/16
13 |
14 | [vertices] [edges]
15 |
16 | options:
17 | vertices
18 |
19 | line color
20 |
21 | color by number of neighbors
22 | color by area
23 |
24 |
25 | """
26 |
27 |
28 | def plot_network(vertices, polys, L, file):
29 | plt.cla()
30 | fig = plt.figure()
31 | ax = fig.add_subplot(1,1,1)
32 | for x,y in vertices:
33 | ax.scatter(x, y, c="m", marker=".", s=50)
34 |
35 | for poly in polys:
36 | indices = poly.indices
37 | for i,index in enumerate(indices):
38 | x1,y1 = vertices[index]
39 | if i == len(indices) - 1:
40 | x2,y2 = vertices[indices[0]]
41 | else:
42 | x2,y2 = vertices[indices[i+1]]
43 |
44 | v1 = np.array((x1,y1))
45 | v2 = np.array((x2,y2))
46 | v2 = v1 + periodic_diff(v2, v1, L)
47 | x2,y2 = v2
48 | ax.plot([x1,x2], [y1,y2], c="c")
49 |
50 | v2 = np.array((x2,y2))
51 | v1 = v2 + periodic_diff(v1, v2, L)
52 | x1,y1 = v1
53 | ax.plot([x1,x2], [y1,y2], c="c")
54 |
55 |
56 | # # plot centers
57 | # x,y = poly.get_center(vertices, L)
58 | # plt.scatter(x,y,color="m", marker="*")
59 |
60 | # remove axis ticks
61 | ax.axes.get_xaxis().set_ticks([])
62 | ax.axes.get_yaxis().set_ticks([])
63 |
64 | ax.axis([0,L[0],0,L[1]])
65 | plt.savefig(file)
66 | plt.close(fig)
67 | return
68 |
69 | def plot_edges(vertices, edges, L):
70 | plt.cla()
71 | for vertex in vertices:
72 | x = vertex[0]
73 | y = vertex[1]
74 | plt.scatter(x, y, c="c")
75 |
76 | for edge in edges:
77 | i1 = edge[0]
78 | i2 = edge[1]
79 | x1,y1 = vertices[i1]
80 | x2,y2 = vertices[i2]
81 | v1 = np.array((x1,y1))
82 | v2 = np.array((x2,y2))
83 | v2 = v1 + periodic_diff(v2, v1, L)
84 | x2,y2 = v2
85 | plt.plot([x1,x2],[y1,y2],c="k")
86 |
87 | plt.axis([0,L[0],0,L[1]])
88 | plt.show()
89 | return
90 |
91 |
92 |
93 |
94 | # vertex_file = sys.argv[1]
95 | # edge_file = sys.argv[2]
96 | # poly_file = sys.argv[3]
97 |
98 | # # lx = 9 * (2 / (3 * (3**0.5)))**0.5
99 | # # ly = 4 * (2 / (3**0.5))**0.5
100 | # L = np.loadtxt("simulation1/L")
101 |
102 | # A0 = 1.
103 | # L = np.array([lx,ly])
104 |
105 | # # get vertices
106 | # vertices = read_vertices(vertex_file)
107 |
108 | # # get edges
109 | # edges = read_edges(edge_file)
110 |
111 | # # get polygons
112 | # poly_indices = read_poly_indices(poly_file)
113 | # polys = build_polygons(poly_indices, A0)
114 |
115 | # file = "test.jpg"
116 | # plot_network(vertices, polys, L, file)
117 |
--------------------------------------------------------------------------------
/steepest_descent.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | import numpy as np
3 | from energy import get_energy
4 | from force import get_forces, move_vertices
5 | from transition import T1_transition
6 |
7 |
8 | def steepest_descent(vertices, edges, polys, parameters):
9 |
10 | epsilon = 10**-6
11 | delta_t = parameters['delta_t']
12 | t = 0.
13 |
14 | count = 0
15 | forces = 10**6
16 | while np.sum(forces**2)**(0.5) > epsilon:
17 |
18 | # get energy for network
19 | energy = get_energy(vertices, polys, edges, parameters)
20 | # print energy
21 |
22 | # get forces for network
23 | forces = get_forces(vertices, polys, edges, parameters)
24 | print np.sum(forces**2)**(0.5)
25 |
26 |
27 | # move vertices
28 | vertices = move_vertices(vertices, forces, parameters)
29 |
30 | # check for T1 transitions
31 | cells, edges = T1_transition(vertices, polys, edges, parameters)
32 |
33 | # add routine to write vertices, energy, forces at every time step
34 | # can be used for plotting routines later...
35 |
36 | t += delta_t
37 |
38 |
39 | return
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | # def steepest_descent(network, vertices, cells, edges, delta_t, epsilon, folder):
74 |
75 | # # keep track of time steps
76 | # time = []
77 | # t = 0
78 |
79 | # # keep track of energy
80 | # energy = []
81 |
82 | # # for T1 transition
83 | # min_dist = 0.2
84 |
85 | # L = network.L
86 |
87 | # # while forces are greater than epsilon
88 | # forces = epsilon**0.5
89 | # count = 0
90 |
91 | # # generate random angle vectors
92 | # for cell in cells:
93 | # cell.theta = rand_angle()
94 |
95 |
96 | # os.mkdir("noise/hex/%s" % folder)
97 | # # f = open("energy/energy.txt", "w+")
98 |
99 | # while count < 50:
100 | # # while np.sum(forces**2)**(0.5) > epsilon:
101 |
102 | # # plot_network(vertices, cells, L, "motility/%d.jpg" % count)
103 |
104 | # # if count % 200 == 0:
105 | # # for cell in cells:
106 | # # cell.theta = rand_angle()
107 |
108 | # # # write cell vertices for MSD
109 |
110 | # os.chdir("noise/hex/%s" % folder)
111 | # np.savetxt("%d.txt" % count, vertices)
112 | # os.chdir("..")
113 | # os.chdir("..")
114 | # os.chdir("..")
115 |
116 | # # get energy for network
117 | # energy = network.get_energy(vertices, cells, edges)
118 |
119 | # # get forces for network
120 | # forces = network.get_forces(vertices, cells, edges)
121 |
122 | # # move vertices with forces
123 | # vertices = network.move_vertices(forces, vertices)
124 |
125 |
126 | # ka = network.parameters['ka']
127 | # A0 = 1.
128 | # print t, energy / (24.*ka*(A0**2)), np.sum(forces**2)**(0.5)
129 | # # norm_energy = np.array(energy / (24.*ka*(A0**2)))
130 | # # f.write("%f\n" % norm_energy)
131 |
132 |
133 | # # new time step
134 | # t += delta_t
135 |
136 | # # # check for T1 transitions
137 | # cells, edges = T1_transition(network, vertices, cells, edges, min_dist)
138 | # count += 1
139 |
140 | # # f.close()
141 | # return vertices
--------------------------------------------------------------------------------
/geometry.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | import numpy as np
3 | from math import sqrt, pi, sin, cos, acos, atan2, floor
4 |
5 |
6 | """
7 |
8 | geometry.py - geometrical formulas
9 |
10 | author: Lexi Signoriello
11 | date: 1/20/16
12 |
13 | vertices - list of vertices
14 | (x0, y0), (x1, y1) ... (xN, yN)
15 |
16 | """
17 |
18 |
19 | # Geometric center of a polygon
20 | def center(vertices):
21 | n = len(vertices)
22 | sumX = 0
23 | sumY = 0
24 | # sum the vectors
25 | for i in range(0,n):
26 | x,y = vertices[i]
27 | sumX += x
28 | sumY += y
29 |
30 | # divide by number of sides
31 | cx = sumX / n
32 | cy = sumY / n
33 |
34 | return cx,cy
35 |
36 |
37 | # Area of a polygon
38 | # http://stackoverflow.com/questions/451426/how-do-i-calculate-the-surface-area-of-a-2d-polygon
39 | def area(vertices):
40 | edges = zip(vertices, vertices[1:] + [vertices[0]])
41 | cross_product = 0
42 | for ((x0, y0), (x1, y1)) in edges:
43 | cross_product += ((x0 * y1) - (x1 * y0))
44 | return 0.5 * abs(cross_product)
45 |
46 |
47 | # Perimeter of a polygon
48 | def perimeter(vertices):
49 | n = len(vertices)
50 | perimeter = 0.
51 | for i in range(0,n):
52 | x0,y0 = vertices[i]
53 | if i == n - 1:
54 | x1,y1 = vertices[0]
55 | if i != n - 1:
56 | x1,y1 = vertices[i+1]
57 | dist = euclidean_distance(x0, y0, x1, y1)
58 | perimeter += dist
59 | return perimeter
60 |
61 |
62 | # Euclidean distance between (x,y) coordinates
63 | def euclidean_distance(x0, y0, x1, y1):
64 | return sqrt((x0 - x1)**2 + (y0 - y1)**2)
65 |
66 |
67 | # Difference with respect to periodic boundaries
68 | def periodic_diff(v1, v2, L):
69 | return ((v1 - v2 + L/2.) % L) - L/2.
70 |
71 |
72 | # Unit vector
73 | def unit_vector(v1, v2):
74 | vector = v1 - v2
75 | dist = euclidean_distance(v1[0], v1[1], v2[0],v2[1])
76 | uv = vector / dist
77 | return uv
78 |
79 |
80 | # assumes 2D
81 | def magnitude(v):
82 | return (v[0]**2 + v[1]**2)**(0.5)
83 |
84 |
85 | # generate random angle theta
86 | def rand_angle():
87 | # generate random number between -pi - pi
88 | theta = np.random.uniform(-pi,pi)
89 | # generate random number between 0 and 2pi
90 | # theta = np.random.uniform(0,2*pi)
91 | return theta
92 |
93 | # returns unit vector
94 | def angle_2_vector(theta):
95 | x = cos(theta)
96 | y = sin(theta)
97 |
98 | # transform to unit vector
99 | v1 = np.array([x,y])
100 | v2 = np.array([0,0])
101 | uv = unit_vector(v1,v2)
102 |
103 | return uv
104 |
105 | def vector_2_angle(x,y):
106 | return atan2(y,x)
107 |
108 |
109 | # in radians [-pi, pi]
110 | # % angle_rad = angle_rad - 2*pi*floor( (angle_rad+pi)/(2*pi) );
111 | def angle_diff(theta1, theta2):
112 | theta = (theta1 - theta2)
113 | return (theta - 2 * pi * floor((theta + pi) / (2 * pi)))
114 |
115 |
116 |
117 | # get angle assuming vertex is p1
118 | # http://stackoverflow.com/questions/1211212/how-to-calculate-an-angle-from-three-points
119 | def get_angle_points(p1,p2,p3):
120 | radian = 0
121 | p12 = sqrt((p1[0]-p2[0])**2 + (p1[1]-p2[1])**2)
122 | p13 = sqrt((p1[0]-p3[0])**2 + (p1[1]-p3[1])**2)
123 | p23 = sqrt((p2[0]-p3[0])**2 + (p2[1]-p3[1])**2)
124 | if p12 != 0 and p13 != 0:
125 | try:
126 | radian = acos( (p12**2 + p13**2 - p23**2)/(2*p12*p13) )
127 | except ValueError:
128 | print "Domain Error"
129 | pass
130 | return radian
131 |
132 | def get_angle_vectors(v1, v2):
133 | theta = np.dot(v1,v2)
134 | theta = theta / (magnitude(v1) * magnitude(v2))
135 | return acos(theta)
136 |
137 |
138 | def radian_2_degrees(theta):
139 | return theta * (360. / (2 * pi))
140 |
141 | # check if counter-clockwise
142 | # change polygon data structure?
143 | def check_counter_clockwise(polygon):
144 | sumEdges = 0
145 | for i,(x,y) in enumerate(polygon):
146 | if i == 0:
147 | x0 = x
148 | y0 = y
149 | if i + 1 != len(polygon):
150 | x2,y2 = polygon[i+1]
151 | if i+1 == len(polygon):
152 | x2 = x0
153 | y2 = y0
154 |
155 | sumEdges += float(x2 - x) / float(y2 + y)
156 |
157 | if sumEdges > 0:
158 | return True
159 | else:
160 | return False
161 |
--------------------------------------------------------------------------------
/force.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | import numpy as np
3 | from geometry import *
4 | from math import pi
5 | import matplotlib.pyplot as plt
6 |
7 | """
8 |
9 | force.py - computes forces in the current configuration
10 | of the vertex model
11 |
12 |
13 | author: Lexi Signoriello
14 | date: 1/20/16
15 |
16 | """
17 |
18 |
19 | def get_forces(vertices, polys, edges, parameters):
20 | # get necessary parameters
21 | lx = parameters['lx']
22 | ly = parameters['ly']
23 | L = np.array([lx,ly])
24 | ka = parameters['ka']
25 | Lambda = parameters['Lambda']
26 | gamma = parameters['gamma']
27 | eta = parameters['eta']
28 | xi = parameters['xi']
29 |
30 | f1 = F_elasticity(vertices, polys, ka, L)
31 | f2 = F_adhesion(vertices, edges, Lambda, L)
32 | f3 = F_contraction(vertices, polys, gamma, L)
33 | f4 = F_motility(vertices, polys, eta, xi)
34 |
35 | return -(f1 + f2 + f3 + f4)
36 |
37 |
38 | def move_vertices(vertices, forces, parameters):
39 | delta_t = parameters['delta_t']
40 | lx = parameters['lx']
41 | ly = parameters['ly']
42 |
43 | vertices = vertices + delta_t * forces
44 | n_vertices = vertices.shape[0]
45 |
46 | # wrap around periodic boundaries
47 | for i in range(0, n_vertices):
48 | x = vertices[i,0]
49 | y = vertices[i,1]
50 |
51 | if x < 0:
52 | # wrap around to right
53 | vertices[i,0] = x + lx
54 | # print x, vertices[i,0]
55 |
56 | if x > lx:
57 | # wrap around to left
58 | vertices[i,0] = x - lx
59 | # print x, vertices[i,0]
60 |
61 | if y < 0:
62 | # wrap around to top
63 | vertices[i,1] = y + ly
64 | # print y, vertices[i,1]
65 |
66 | if y > ly:
67 | # wrap around to bottom
68 | vertices[i,1] = y - ly
69 | # print y, vertices[i,1]
70 |
71 |
72 | return vertices
73 |
74 |
75 |
76 | def get_clockwise(index, indices, vertices, L):
77 |
78 | # get position of vertex in list
79 | pos = [i for i,x in enumerate(indices) if x == index]
80 | pos = pos[0]
81 |
82 | # clockwise is position to right
83 | # wrap around to 0 if at end of the list
84 | if pos == len(indices) - 1:
85 | pos = 0
86 | else:
87 | pos += 1
88 |
89 | # compute vertex wrt periodic boundaries
90 | v0 = vertices[index]
91 | v = vertices[indices[pos]]
92 | vc = v0 + periodic_diff(v, v0, L)
93 |
94 | return vc
95 |
96 |
97 |
98 | def get_counter_clockwise(index, indices, vertices, L):
99 |
100 | # get position of vertex in list
101 | pos = [i for i,x in enumerate(indices) if x == index]
102 | pos = pos[0]
103 |
104 | # clockwise is position to left
105 | # wrap around to end of list if first value
106 | if pos == 0:
107 | pos = len(indices) - 1
108 | else:
109 | pos -= 1
110 |
111 | v0 = vertices[index]
112 | v = vertices[indices[pos]]
113 | vcc = v0 + periodic_diff(v, v0, L)
114 |
115 | return vcc
116 |
117 |
118 | # Force on vertex due to elasticity
119 | def F_elasticity(vertices, polys, ka, L):
120 | n_vertices = len(vertices)
121 |
122 | # evert vertex has an associated force
123 | forces = np.zeros((n_vertices, 2))
124 |
125 | # iterate over vertices and get force
126 | for i,vertex in enumerate(vertices):
127 |
128 | # find polys with this vertex
129 | for poly in polys:
130 |
131 | # if this vertex is in current poly
132 | # compute force contributed from this poly
133 | if i in poly.indices:
134 |
135 | # get clockwise vector
136 | vc = get_clockwise(i, poly.indices, vertices, L)
137 |
138 | # get counter-clockwise vector
139 | vcc = get_counter_clockwise(i, poly.indices, vertices, L)
140 |
141 | # get the difference vector
142 | diff = vc - vcc
143 |
144 | # compute perpendicular vector
145 | # assure correct direction (pointing towards vertex)
146 | perp_matrix = np.zeros((2,2))
147 | perp_matrix[0,1] = 1.
148 | perp_matrix[1,0] = -1.
149 |
150 | f = -0.5 * np.dot(perp_matrix, diff)
151 |
152 | # force contributed from this poly stored in f
153 | coeff = ka * (poly.A0 - poly.get_area(vertices, L))
154 |
155 | forces[i,:] += coeff * f
156 |
157 |
158 | return forces
159 |
160 |
161 |
162 | def F_contraction(vertices, polys, gamma, L):
163 |
164 | # every vertex has an associated force
165 | n_vertices = len(vertices)
166 | forces = np.zeros((n_vertices, 2))
167 |
168 | for i,vertex in enumerate(vertices):
169 |
170 | # find polys with this vertex
171 | for poly in polys:
172 |
173 | if i in poly.indices:
174 |
175 | # get clockwise vector
176 | vc = get_clockwise(i, poly.indices, vertices, L)
177 | uvc = unit_vector(vertex, vc)
178 |
179 | # get counter-clockwise vector
180 | vcc = get_counter_clockwise(i, poly.indices, vertices, L)
181 | uvcc = unit_vector(vcc, vertex)
182 |
183 | # get perimeter for this poly
184 | p = poly.get_perim(vertices, L)
185 |
186 | forces[i,:] += (gamma * p) * (uvc - uvcc)
187 |
188 | return forces
189 |
190 | def F_adhesion(vertices, edges, Lambda, L):
191 |
192 | # every vertex has an associated force
193 | n_vertices = len(vertices)
194 | forces = np.zeros((n_vertices, 2))
195 |
196 | for edge in edges:
197 | i1 = edge[0]
198 | i2 = edge[1]
199 | v1 = vertices[i1]
200 | vertex2 = vertices[i2]
201 | v2 = v1 + periodic_diff(vertex2, v1, L)
202 | uv = unit_vector(v1, v2)
203 | forces[i1,:] += Lambda * uv
204 |
205 | return forces
206 |
207 | # Force to move vertices of polys in particular direction
208 | def F_motility(vertices, polys, eta, xi):
209 |
210 |
211 | n_vertices = len(vertices)
212 | forces = np.zeros((n_vertices, 2))
213 |
214 | # find neighbors for every poly
215 | # defined as any two polys that share a vertex
216 | avg_angles = np.zeros((len(polys), 2))
217 |
218 | neighbor_count = np.ones(len(polys))
219 |
220 | for i,poly in enumerate(polys):
221 | avg_angles[i, :] += angle_2_vector(poly.theta)
222 | for j,poly2 in enumerate(polys):
223 | if i != j:
224 | a = poly.indices
225 | b = poly2.indices
226 | if any(k in a for k in b) == True:
227 | avg_angles[i, :] += angle_2_vector(poly2.theta)
228 | neighbor_count[i] += 1
229 |
230 | for i,poly in enumerate(polys):
231 |
232 | # noise variable
233 | nx = np.random.uniform(-pi,pi)
234 | ny = np.random.uniform(-pi,pi)
235 | n = np.array([nx,ny])
236 |
237 | # average all of the unit vectors for angles
238 | avg = (avg_angles[i,:] / neighbor_count[i])
239 |
240 | # add this force direction for every vertex in current poly
241 | for index in poly.indices:
242 | forces[index, :] += xi * (avg + (eta * n))
243 |
244 | # theta = avg + eta * noise
245 | poly.theta = vector_2_angle(avg[0] + eta * n[0], avg[1] + eta * n[1])
246 |
247 | return forces
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 | # visualization for average vector
262 |
263 | # plt.plot([0, avg_angles[i,0]],[0,avg_angles[i,1]], color="k")
264 |
265 | # v = angle_2_vector(poly2.theta)
266 | # plt.plot([0,v[0]],[0,v[1]],color="k")
267 | # print avg_angles[i,:] / neighbor_count[i]
268 | # print magnitude(avg_angles[i,:] / neighbor_count
269 |
270 | # v_avg = avg_angles[i,:] / neighbor_count[i]
271 | # print magnitude(v_avg)
272 | # print vector_2_angle(v_avg[0], v_avg[1])
273 | # plt.plot([0,v_avg[0]],[0,v_avg[1]],color="m")
274 | # v_avg_unit = unit_vector(v_avg, np.array([0,0]))
275 | # plt.plot([0,v_avg_unit[0]],[0,v_avg_unit[1]],color="g")
276 | # plt.plot([0,v_avg[0]],[0,v_avg[1]],color="m")
277 | # plt.show()
278 | # eetat()
279 |
280 |
281 |
--------------------------------------------------------------------------------
/transition.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | import numpy as np
3 | from Polygon import Polygon
4 | from geometry import periodic_diff
5 | from energy import *
6 | import copy
7 |
8 |
9 | """
10 |
11 | transition.py - implements T1 transition for short bond lengths
12 |
13 | author: Lexi Signoriello
14 | date: 2/12/16
15 |
16 | 4 polys involved in transition are 1-4 counter-clockwise order
17 |
18 | Cells defined such that:
19 | Cell 0: i4, i1, i2, i5
20 | Cell 1: i3, i1, i4
21 | Cell 2: i6, i2, i1, i3
22 | Cell 3: i5, i2, i6
23 |
24 |
25 | Edges defined such that:
26 | Edge 0: i1 - i2
27 | Edge 1: i1 - i3
28 | Edge 2: i1 - i4
29 | Edge 3: i2 - i1
30 | Edge 4: i2 - i5
31 | Edge 5: i2 - i6
32 | Edge 6: i3 - i1 # reverse edges
33 | Edge 7: i4 - i1
34 | Edge 8: i5 - i2
35 | Edge 9: i6 - i2
36 |
37 |
38 | """
39 |
40 |
41 |
42 | def get_6_indices(polys, i1, i2, poly_ids):
43 | polys_copy = []
44 | for i in poly_ids:
45 | poly = copy.deepcopy(polys[i])
46 | polys_copy.append(poly)
47 |
48 | # define polys
49 | poly_0 = polys_copy[0]
50 | poly_1 = polys_copy[1]
51 | poly_2 = polys_copy[2]
52 | poly_3 = polys_copy[3]
53 |
54 | # Find indices wrt Cell 1
55 | pos = int(np.where(poly_1.indices == i1)[0])
56 | # i3: poly 1 before i1
57 | if pos == 0:
58 | i_left = len(poly_1.indices) - 1
59 | else:
60 | i_left = pos - 1
61 | i3 = poly_1.indices[i_left]
62 | # i4: poly 1 after i1
63 | if pos == len(poly_1.indices) - 1:
64 | i_right = 0
65 | else:
66 | i_right = pos + 1
67 | i4 = poly_1.indices[i_right]
68 | # i5: poly 3 before i2
69 | pos = int(np.where(poly_3.indices == i2)[0])
70 | if pos == 0:
71 | i_left = len(poly_3.indices) - 1
72 | else:
73 | i_left = pos - 1
74 | i5 = poly_3.indices[i_left]
75 | # i6: poly 3 after i2
76 | if pos == len(poly_3.indices) - 1:
77 | i_right = 0
78 | else:
79 | i_right = pos + 1
80 | i6 = poly_3.indices[i_right]
81 |
82 | indices = [i1,i2,i3,i4,i5,i6]
83 |
84 | return indices
85 |
86 |
87 |
88 | # get polys and edges associated with short bond length
89 | def T1_0(polys, i1, i2, poly_ids, indices):
90 | polys_0 = []
91 |
92 | for i in poly_ids:
93 | # copy poly so it can be manipulated without changing
94 | # current configuation
95 | poly = copy.deepcopy(polys[i])
96 | polys_0.append(poly)
97 |
98 | # define polys
99 | poly_0 = polys_0[0]
100 | poly_1 = polys_0[1]
101 | poly_2 = polys_0[2]
102 | poly_3 = polys_0[3]
103 |
104 | i1 = indices[0]
105 | i2 = indices[1]
106 | i3 = indices[2]
107 | i4 = indices[3]
108 | i5 = indices[4]
109 | i6 = indices[5]
110 |
111 | edges_0 = np.zeros((10,2))
112 | # Edge 0: i1 - i2
113 | edges_0[0,0] = i1
114 | edges_0[0,1] = i2
115 |
116 | # Edge 1: i1 - i3
117 | edges_0[1,0] = i1
118 | edges_0[1,1] = i3
119 |
120 | # Edge 2: i1 - i4
121 | edges_0[2,0] = i1
122 | edges_0[2,1] = i4
123 |
124 | # Edge 3: i2 - i1
125 | edges_0[3,0] = i2
126 | edges_0[3,1] = i1
127 |
128 | # Edge 4: i2 - i5
129 | edges_0[4,0] = i2
130 | edges_0[4,1] = i5
131 |
132 | # Edge 5: i2 - i6
133 | edges_0[5,0] = i2
134 | edges_0[5,1] = i6
135 |
136 | # Edge 6: i3 - i1 # reverse edges
137 | edges_0[6,0] = i3
138 | edges_0[6,1] = i1
139 |
140 | # Edge 7: i4 - i1
141 | edges_0[7,0] = i4
142 | edges_0[7,1] = i1
143 |
144 | # Edge 8: i5 - i2
145 | edges_0[8,0] = i5
146 | edges_0[8,1] = i2
147 |
148 | # Edge 9: i6 - i2
149 | edges_0[9,0] = i6
150 | edges_0[9,1] = i2
151 |
152 | return polys_0, edges_0
153 |
154 | # get polys and edges associated with
155 | def T1_left(polys, i1, i2, poly_ids, indices):
156 |
157 | # Cells
158 | polys_l = []
159 | # ids in correct order already
160 | for i in poly_ids:
161 | poly = copy.deepcopy(polys[i])
162 | polys_l.append(poly)
163 |
164 | # define polys
165 | poly_0 = polys_l[0]
166 | poly_1 = polys_l[1]
167 | poly_2 = polys_l[2]
168 | poly_3 = polys_l[3]
169 |
170 | # define indices
171 | i1 = indices[0]
172 | i2 = indices[1]
173 | i3 = indices[2]
174 | i4 = indices[3]
175 | i5 = indices[4]
176 | i6 = indices[5]
177 |
178 | # Cell 0: remove i2
179 | pos = int(np.where(poly_0.indices == i2)[0])
180 | indices = np.delete(poly_0.indices, pos)
181 | polys_l[0].indices = indices
182 |
183 |
184 | # Cell 1: insert i2 before i1
185 | pos = int(np.where(poly_1.indices == i1)[0])
186 | left_indices = poly_1.indices[:pos]
187 | right_indices = poly_1.indices[pos:]
188 | indices = np.concatenate((left_indices, [i2], right_indices))
189 | polys_l[1].indices = indices
190 |
191 | # Cell 2: remove i1
192 | pos = int(np.where(poly_2.indices == i1)[0])
193 | indices = np.delete(poly_2.indices, pos)
194 | polys_l[2].indices = indices
195 |
196 | # Cell 3: insert i1 before i2
197 | pos = int(np.where(poly_3.indices == i2)[0])
198 | left_indices = poly_3.indices[:pos]
199 | right_indices = poly_3.indices[pos:]
200 | indices = np.concatenate((left_indices, [i1], right_indices))
201 | polys_l[3].indices = indices
202 |
203 |
204 | # Edges
205 | edges_l = np.zeros((10,2))
206 | # Edge 0: i1 - i2
207 | edges_l[0,0] = i1
208 | edges_l[0,1] = i2
209 |
210 | # Edge 1: i2 - i3
211 | edges_l[1,0] = i2
212 | edges_l[1,1] = i3
213 |
214 | # Edge 2: i1 - i4
215 | edges_l[2,0] = i1
216 | edges_l[2,1] = i4
217 |
218 | # Edge 3: i2 - i1
219 | edges_l[3,0] = i2
220 | edges_l[3,1] = i1
221 |
222 | # Edge 4: i1 - i5
223 | edges_l[4,0] = i1
224 | edges_l[4,1] = i5
225 |
226 | # Edge 5: i2 - i6
227 | edges_l[5,0] = i2
228 | edges_l[5,1] = i6
229 |
230 | # Edge 6: i3 - i2 # reverse edges
231 | edges_l[6,0] = i3
232 | edges_l[6,1] = i2
233 |
234 | # Edge 7: i4 - i1
235 | edges_l[7,0] = i4
236 | edges_l[7,1] = i1
237 |
238 | # Edge 8: i5 - i1
239 | edges_l[8,0] = i5
240 | edges_l[8,1] = i1
241 |
242 | # Edge 9: i6 - i2
243 | edges_l[9,0] = i6
244 | edges_l[9,1] = i2
245 |
246 |
247 | return polys_l, edges_l
248 |
249 | def T1_right(polys, i1, i2, poly_ids, indices):
250 |
251 | polys_r = []
252 | for i in poly_ids:
253 | poly = copy.deepcopy(polys[i])
254 | polys_r.append(poly)
255 |
256 | # define polys
257 | poly_0 = polys_r[0]
258 | poly_1 = polys_r[1]
259 | poly_2 = polys_r[2]
260 | poly_3 = polys_r[3]
261 |
262 | # define indices
263 | i1 = indices[0]
264 | i2 = indices[1]
265 | i3 = indices[2]
266 | i4 = indices[3]
267 | i5 = indices[4]
268 | i6 = indices[5]
269 |
270 | # Cell 0: remove i1
271 | pos = int(np.where(poly_0.indices == i1)[0])
272 | indices = np.delete(poly_0.indices, pos)
273 | polys_r[0].indices = indices
274 |
275 |
276 | # Cell 1: insert i2 after i1
277 | pos = int(np.where(poly_1.indices == i1)[0])
278 | left_indices = poly_1.indices[:pos+1]
279 | right_indices = poly_1.indices[pos+1:]
280 | indices = np.concatenate((left_indices, [i2], right_indices))
281 | polys_r[1].indices = indices
282 |
283 | # Cell 2: remove i2
284 | pos = int(np.where(poly_2.indices == i2)[0])
285 | indices = np.delete(poly_2.indices, pos)
286 | polys_r[2].indices = indices
287 |
288 | # Cell 3: insert i1 after i2
289 | pos = int(np.where(poly_3.indices == i2)[0])
290 | left_indices = poly_3.indices[:pos+1]
291 | right_indices = poly_3.indices[pos+1:]
292 | indices = np.concatenate((left_indices, [i1], right_indices))
293 | polys_r[3].indices = indices
294 |
295 | # # Edges
296 | edges_r = np.zeros((10,2))
297 | # Edge 0: i1 - i2
298 | edges_r[0,0] = i1
299 | edges_r[0,1] = i2
300 |
301 | # Edge 1: i1 - i3
302 | edges_r[1,0] = i1
303 | edges_r[1,1] = i3
304 |
305 | # Edge 2: i1 - i6
306 | edges_r[2,0] = i1
307 | edges_r[2,1] = i6
308 |
309 | # Edge 3: i2 - i1
310 | edges_r[3,0] = i2
311 | edges_r[3,1] = i1
312 |
313 | # Edge 4: i2 - i5
314 | edges_r[4,0] = i2
315 | edges_r[4,1] = i5
316 |
317 | # Edge 5: i2 - i4
318 | edges_r[5,0] = i2
319 | edges_r[5,1] = i4
320 |
321 | # Edge 6: i3 - i1 # reverse edges
322 | edges_r[6,0] = i3
323 | edges_r[6,1] = i1
324 |
325 | # Edge 7: i4 - i2
326 | edges_r[7,0] = i4
327 | edges_r[7,1] = i2
328 |
329 | # Edge 8: i5 - i2
330 | edges_r[8,0] = i5
331 | edges_r[8,1] = i2
332 |
333 | # Edge 9: i6 - i1
334 | edges_r[9,0] = i6
335 | edges_r[9,1] = i1
336 |
337 |
338 | return polys_r, edges_r
339 |
340 |
341 | # # find 4 polys involved with 2 vertices
342 | # Labeled polys 0-3 in counter-clockwise order
343 | # Cell 0 and Cell 3 are neighbors
344 | def get_4_polys(polys, i1, i2):
345 |
346 | poly_ids = np.zeros(4).astype(int)
347 | poly_ids.fill(-1) # catch errors later
348 |
349 | for poly in polys:
350 | # Cell 0 or Cell 2
351 | # Current neighboring polys
352 | # Cell 1 should have i1 before i2 in counter-clockwise orde
353 | if i1 in poly.indices and i2 in poly.indices:
354 | pos1 = np.where(poly.indices == i1)
355 | pos2 = np.where(poly.indices == i2)
356 |
357 | if pos1 == len(poly.indices) - 1:
358 | pos1 = -1
359 | if pos2 == len(poly.indices) - 1:
360 | pos2 = -1
361 |
362 | # if Cell 1: i1 is before i2
363 | if pos1 < pos2:
364 | poly_ids[0] = poly.id
365 | # if Cell 3: i2 is before i1
366 | if pos2 < pos1:
367 | poly_ids[2] = poly.id
368 |
369 | # Cell 3
370 | if i2 in poly.indices and i1 not in poly.indices:
371 | poly_ids[3] = poly.id
372 | # Cell 1
373 | if i1 in poly.indices and i2 not in poly.indices:
374 | poly_ids[1] = poly.id
375 |
376 | return poly_ids
377 |
378 |
379 |
380 | def T1_transition(vertices, polys, edges, parameters):
381 |
382 |
383 | lx = parameters['lx']
384 | ly = parameters['ly']
385 | L = np.array([lx,ly])
386 | lmin = parameters['lmin']
387 |
388 | reverse = []
389 |
390 | for edge in edges:
391 | i1 = edge[0]
392 | i2 = edge[1]
393 |
394 | v1 = vertices[i1]
395 | vertex2 = vertices[i2]
396 | v2 = v1 + periodic_diff(vertex2, v1, L)
397 |
398 | dist = euclidean_distance(v1[0], v1[1], v2[0], v2[1])
399 |
400 | if dist < lmin and (i1,i2) not in reverse:
401 | print "T1", i1, i2, dist
402 | poly_ids = get_4_polys(polys, i1, i2)
403 | if -1 in poly_ids:
404 | pass
405 | else:
406 | # find minimum configuration
407 | reverse.append((i2,i1))
408 |
409 | # 6 indices for vertices involved in transition
410 | indices = get_6_indices(polys, i1, i2, poly_ids)
411 |
412 | # original configuration
413 | polys_0, edges_0 = T1_0(polys, i1, i2, poly_ids, indices)
414 | E0 = get_energy(vertices, polys_0, edges_0, parameters)
415 |
416 | # left T1 transition
417 | polys_l, edges_l = T1_left(polys, i1, i2, poly_ids, indices)
418 | E_left = get_energy(vertices, polys_l, edges_l, parameters)
419 |
420 | # # right T1 transition
421 | polys_r, edges_r = T1_right(polys, i1, i2, poly_ids, indices)
422 | E_right = get_energy(vertices, polys_r, edges_r, parameters)
423 |
424 |
425 | # get minimum
426 | min_energy = np.min((E0, E_left, E_right))
427 | min_i = np.argmin((E0, E_left, E_right))
428 | print min_i
429 |
430 | # # do nothing - same configuration
431 | if min_i == 0:
432 | pass
433 |
434 | if min_i == 1:
435 | set_T1_left(polys, polys_l, poly_ids, edges, indices)
436 |
437 | if min_i == 2:
438 | set_T1_right(polys, polys_r, poly_ids, edges, indices)
439 |
440 | return polys, edges
441 |
442 |
443 | def set_T1_left(polys, polys_l, poly_ids, edges, indices):
444 | # set new poly indices
445 | for i,poly in enumerate(polys_l):
446 | polys[poly_ids[i]].indices = poly.indices
447 |
448 | # set new edges
449 | i1 = indices[0]
450 | i2 = indices[1]
451 | i3 = indices[2]
452 | i5 = indices[4]
453 | for i,edge in enumerate(edges):
454 |
455 | # i1 - i3 becomes i2 - i3
456 | if edge[0] == i1 and edge[1] == i3:
457 | edges[i][0] = i2
458 |
459 | # i2 - i5 becomes i1 - i5
460 | if edge[0] == i2 and edge[1] == i5:
461 | edges[i][0] = i1
462 |
463 | # i3 - i1 becomes i3 - i2
464 | if edge[0] == i3 and edge[1] == i1:
465 | edges[i][1] = i2
466 |
467 | # i5 - i2 becomes i5 - i1
468 | if edge[0] == i5 and edge[1] == i2:
469 | edges[i][1] = i1
470 |
471 | return
472 |
473 |
474 | def set_T1_right(polys, polys_r, poly_ids, edges, indices):
475 |
476 | # set new poly indices
477 | for i,poly in enumerate(polys_r):
478 | polys[poly_ids[i]].indices = poly.indices
479 |
480 |
481 | # set new edges
482 | i1 = indices[0]
483 | i2 = indices[1]
484 | i4 = indices[3]
485 | i6 = indices[5]
486 |
487 | for i,edge in enumerate(edges):
488 |
489 | # i1 - i4 becomes i2 - i4
490 | if edge[0] == i1 and edge[1] == i4:
491 | edges[i][0] = i2
492 |
493 | # i2 - i6 becomes i1 - i6
494 | if edge[0] == i2 and edge[1] == i6:
495 | edges[i][0] = i1
496 |
497 | # i4 - i1 becomes i4 - i2
498 | if edge[0] == i4 and edge[1] == i1:
499 | edges[i][1] = i2
500 |
501 | # i6 - i2 becomes i6 - i1
502 | if edge[0] == i6 and edge[1] == i2:
503 | edges[i][1] = i1
504 |
505 | return
506 |
507 |
508 |
509 |
510 | def T2_transition(network, vertices, polys, edges, min_area):
511 | pass
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
--------------------------------------------------------------------------------