diff --git a/README.md b/README.md
index 6c2bdb4..123b5f3 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@ numpy==1.21.5
seaborn==0.12.2
```
## Usage
-### Single Triangle
+### Single Terahedron
```shell
python main_single_2d.py
```
@@ -44,18 +44,16 @@ Args
'--fix', type=bool, default=True, help='Fix a point on the wall'
'--implict', action='store_true', help='Implict Euler Method, for STVK and Neohookean'
```
-#### Visual Results
-**
Symplectic Euler Methods
**
-
+####Visual Results
+**Symplectic Euler Methods**

-

-**Implict Euler Methods
**
+**Implict Euler Methods**

-### Multiple Cubes
+### Multiple Terahedrons
```shell
python main_multiple_2d.py
```
@@ -75,24 +73,29 @@ Args
'--mass', type=float, default=1.0, help='Mass of the point'
'--implict', action='store_true', help='Implict Euler Method, for STVK and Neohookean'
```
-#### Visual Results
-Symplectic Euler Methods
-
-**Linear Elasticity
**
+####Visual Results
+Symplectic Euler Methods
+**Linear Elasticity**

-**St. Venant-Kirchhoff
**
-
+**St. Venant-Kirchhoff **

-**Corotated linear elasticity
**
+**Corotated linear elasticity**
+
-
+**Neohookean elasticity**
+
-**Neohookean elasticity
**
+Implict Euler Methods
+
+**St. Venant-Kirchhoff **
+
+
+**Neohookean elasticity **
+
-
## Reference
[FEM Simulation of 3D Deformable Solids: A practitioner's guide to theory, discretization and model reduction](http://viterbi-web.usc.edu/~jbarbic/femdefo/)
diff --git a/fem_2d.py b/fem_2d.py
index 2708a88..8a8a934 100644
--- a/fem_2d.py
+++ b/fem_2d.py
@@ -1,5 +1,6 @@
from matplotlib import pyplot as plt
from matplotlib import cm
+from jacobin import JacoBinSolver
import numpy as np
import imageio
import shutil
@@ -14,7 +15,7 @@ def judge(point, rect_pos):
return False
if point[0] > rect_pos[0][0] + rect_pos[1][0]:
return False
- if point[1] > rect_pos[0][1] +rect_pos[1][1]:
+ if point[1] > rect_pos[0][1] + rect_pos[1][1]:
return False
return True
@@ -44,8 +45,9 @@ def plot_voxel(node_pos, element_num, element_idx, empty_voxel_index):
element_y = node_pos[element_idx[ie,:],1]
dx = np.array([[element_x[1] - element_x[0],element_x[2] - element_x[0]],
[element_y[1] - element_y[0],element_y[2] - element_y[0]]])
- current_area = np.linalg.det(dx)*0.5
- plt.fill(element_x,element_y, c=cm.Blues(0.5/current_area))
+ # current_area = np.linalg.det(dx)*0.5
+ # plt.fill(element_x,element_y, c=cm.Blues(0.5/current_area))
+ plt.fill(element_x,element_y)
# Deformation
def Afine_2D(points, theta, tx, ty, sx, sy):
@@ -198,7 +200,8 @@ def implicit_euler_stvk(args, B_m, F, strain, nodal_force,nodal_vel, multiple=Fa
b[n*2+d] = args.mass * nodal_vel[n,d] + args.dt * nodal_force[n,d]
# X
- X = np.dot(np.linalg.inv(A), b)
+ #XX = np.dot(np.linalg.inv(A), b)
+ X = JacoBinSolver(A, b)
for n in range(3):
if args.fix and n == 0:
continue
@@ -280,6 +283,7 @@ def solver(args,A,K,b,node_vel,node_force):
b[i*2 + 1] = args.mass * node_vel[i,1] + args.dt * node_force[i,1]
X = np.dot(np.linalg.inv(A),b)
+ # X = JacoBinSolver(A, b,iter=1000)
return X
# Simulation for a single triangle
@@ -316,7 +320,10 @@ def run_fem_simulation_single(args):
# Position after deformation
x = Afine_2D(args.ref_node_pos, args.theta, args.tx, args.ty, args.sx, args.sy)
-
+
+ # Reflection
+ x = np.array([[3,2],[4,3],[3,3]], dtype=float)
+
# Plot the triangle after deformation
plt.fill(x[:,0], x[:,1], 'b')
plt.text(0.01, 6.8, f'Init Area: {init_area}', fontsize=15, color='red')
@@ -590,7 +597,7 @@ def run_fem_simulation_multiple(args):
raise
H = -init_area * np.dot(piola,D_m[ie].transpose())
-
+
# Force 1, the first column of H
f1 = np.array([H[0,0],H[1,0]])
@@ -601,9 +608,11 @@ def run_fem_simulation_multiple(args):
f0 = - f1 - f2
nodal_force[element_idx[ie,0],:] += f0
+ #print(nodal_force[element_idx[ie,0],:])
nodal_force[element_idx[ie,1],:] += f1
+ #print(nodal_force[element_idx[ie,1],:])
nodal_force[element_idx[ie,2],:] += f2
-
+ #print(nodal_force[element_idx[ie,2],:])
if args.implict:
if args.model == 1:
dH = implicit_euler_stvk(args, D_m[ie], F, strain, nodal_force, node_vel, multiple=True)
@@ -618,24 +627,31 @@ def run_fem_simulation_multiple(args):
didx = n * 2 + d
idx = element_idx[ie,1] * 2
K[idx,kidx] += dH[didx,0,0]
+ #print(K[idx,kidx])
idx = element_idx[ie,1] * 2 + 1
K[idx,kidx] += dH[didx,1,0]
+ #print(K[idx,kidx])
idx = element_idx[ie,2] * 2
K[idx,kidx] += dH[didx,0,1]
+ #print(K[idx,kidx])
idx = element_idx[ie,2] * 2 + 1
K[idx,kidx] += dH[didx,1,1]
+ #print(K[idx,kidx])
idx = element_idx[ie,0] * 2
K[idx,kidx] += - dH[didx,0,0] - dH[didx,0,1]
+ #print(K[idx,kidx])
idx = element_idx[ie,0] * 2 + 1
K[idx,kidx] += - dH[didx,1,0] - dH[didx,1,1]
+ #print(K[idx,kidx])
'''Step 6. Update position'''
# Update
if not args.implict:
for i in range(node_num):
- acc = nodal_force[i]/args.mass + Gravity
+ acc = (nodal_force[i] + Gravity)/args.mass
node_vel[i] += args.dt*acc
node_vel[i] *= np.exp(-args.dt*1)
+ node_pos[i] += args.dt*node_vel[i]
else:
# Add Gravity
for i in range(node_num):
@@ -647,7 +663,10 @@ def run_fem_simulation_multiple(args):
node_vel[i,0] = X[i * 2 + 0]
node_vel[i,1] = X[i * 2 + 1]
node_pos[i,:] += node_vel[i,:] * args.dt
- # node_vel[i] *= np.exp(-args.dt * 1.0)
+ node_vel[i] *= np.exp(-args.dt * 1.0)
+ K = np.zeros((krow,krow))
+ A = np.zeros((krow,krow))
+ b = np.zeros((krow))
# bend
if args.mode == "bend":
@@ -661,10 +680,21 @@ def run_fem_simulation_multiple(args):
# Ball
disp = node_pos[i] - args.ball_pos
disp2 = np.sum(np.square(disp))
+
+
if disp2 <= args.ball_radius**2:
+ vec = np.array([1,0])
+ disp_m = np.sqrt(disp.dot(disp))
+ vec_m = np.sqrt(vec.dot(vec))
+ cos_theta = disp.dot(vec)/(disp_m*vec_m)
+ angle=np.arccos(cos_theta)
+ modi_x = args.ball_pos[0] + args.ball_radius*cos_theta
+ modi_y = args.ball_radius*np.sin(angle)
NoV = node_vel[i].dot(disp)
if NoV < 0:
node_vel[i] -= NoV * disp / disp2
+ node_pos[i] = np.array([modi_x,modi_y])
+
# Rectangle boundary condition
# if rect_collision(node_pos[i], args.rectangle_pos):
# if args.rectangle_pos[0][0] < node_pos[i][0] < (args.rectangle_pos[0][0]+args.rectangle_pos[1][0]):
@@ -680,7 +710,7 @@ def run_fem_simulation_multiple(args):
node_pos[i][j] = 15
node_vel[i][j] = -0.99*node_vel[i][j]
- node_pos[i] += args.dt*node_vel[i]
+
# ax.add_patch(args.rectangle)
ax.add_patch(args.semicircle)
diff --git a/gifs/Multiple_2D_Co-rotated_implicit_False_bend_8.gif b/gifs/Multiple_2D_Co-rotated_implicit_False_bend_8.gif
index 7cc7d2d..0d65b85 100644
Binary files a/gifs/Multiple_2D_Co-rotated_implicit_False_bend_8.gif and b/gifs/Multiple_2D_Co-rotated_implicit_False_bend_8.gif differ
diff --git a/gifs/Multiple_2D_Co-rotated_implicit_False_fall_8.gif b/gifs/Multiple_2D_Co-rotated_implicit_False_fall_8.gif
index 6316545..2dcf252 100644
Binary files a/gifs/Multiple_2D_Co-rotated_implicit_False_fall_8.gif and b/gifs/Multiple_2D_Co-rotated_implicit_False_fall_8.gif differ
diff --git a/gifs/Multiple_2D_Linear_implicit_False_bend_8.gif b/gifs/Multiple_2D_Linear_implicit_False_bend_8.gif
index f1acdf3..494c9f5 100644
Binary files a/gifs/Multiple_2D_Linear_implicit_False_bend_8.gif and b/gifs/Multiple_2D_Linear_implicit_False_bend_8.gif differ
diff --git a/gifs/Multiple_2D_Linear_implicit_False_fall_8.gif b/gifs/Multiple_2D_Linear_implicit_False_fall_8.gif
index 536a805..b55983c 100644
Binary files a/gifs/Multiple_2D_Linear_implicit_False_fall_8.gif and b/gifs/Multiple_2D_Linear_implicit_False_fall_8.gif differ
diff --git a/gifs/Multiple_2D_Neohookean_implicit_False_bend_8.gif b/gifs/Multiple_2D_Neohookean_implicit_False_bend_8.gif
index f808dea..1d2a49e 100644
Binary files a/gifs/Multiple_2D_Neohookean_implicit_False_bend_8.gif and b/gifs/Multiple_2D_Neohookean_implicit_False_bend_8.gif differ
diff --git a/gifs/Multiple_2D_Neohookean_implicit_False_fall_8.gif b/gifs/Multiple_2D_Neohookean_implicit_False_fall_8.gif
index 0800d8e..2cc0b00 100644
Binary files a/gifs/Multiple_2D_Neohookean_implicit_False_fall_8.gif and b/gifs/Multiple_2D_Neohookean_implicit_False_fall_8.gif differ
diff --git a/gifs/Multiple_2D_Neohookean_implicit_True_bend_8_inv.gif b/gifs/Multiple_2D_Neohookean_implicit_True_bend_8_inv.gif
new file mode 100644
index 0000000..c047546
Binary files /dev/null and b/gifs/Multiple_2D_Neohookean_implicit_True_bend_8_inv.gif differ
diff --git a/gifs/Multiple_2D_Neohookean_implicit_True_bend_8_jacobin.gif b/gifs/Multiple_2D_Neohookean_implicit_True_bend_8_jacobin.gif
new file mode 100644
index 0000000..00842a9
Binary files /dev/null and b/gifs/Multiple_2D_Neohookean_implicit_True_bend_8_jacobin.gif differ
diff --git a/gifs/Multiple_2D_Neohookean_implicit_True_fall_8.gif b/gifs/Multiple_2D_Neohookean_implicit_True_fall_8.gif
new file mode 100644
index 0000000..71ff527
Binary files /dev/null and b/gifs/Multiple_2D_Neohookean_implicit_True_fall_8.gif differ
diff --git a/gifs/Multiple_2D_STVK_implicit_False_bend_8.gif b/gifs/Multiple_2D_STVK_implicit_False_bend_8.gif
index cd6a647..43ad9c0 100644
Binary files a/gifs/Multiple_2D_STVK_implicit_False_bend_8.gif and b/gifs/Multiple_2D_STVK_implicit_False_bend_8.gif differ
diff --git a/gifs/Multiple_2D_STVK_implicit_False_fall_8.gif b/gifs/Multiple_2D_STVK_implicit_False_fall_8.gif
index 249a06d..9a46010 100644
Binary files a/gifs/Multiple_2D_STVK_implicit_False_fall_8.gif and b/gifs/Multiple_2D_STVK_implicit_False_fall_8.gif differ
diff --git a/gifs/Multiple_2D_STVK_implicit_True_bend_8.gif b/gifs/Multiple_2D_STVK_implicit_True_bend_8.gif
new file mode 100644
index 0000000..224b446
Binary files /dev/null and b/gifs/Multiple_2D_STVK_implicit_True_bend_8.gif differ
diff --git a/gifs/Multiple_2D_STVK_implicit_True_fall_0.gif b/gifs/Multiple_2D_STVK_implicit_True_fall_0.gif
deleted file mode 100644
index 1d7f73a..0000000
Binary files a/gifs/Multiple_2D_STVK_implicit_True_fall_0.gif and /dev/null differ
diff --git a/gifs/Multiple_2D_STVK_implicit_True_fall_8.gif b/gifs/Multiple_2D_STVK_implicit_True_fall_8.gif
new file mode 100644
index 0000000..7c7c40d
Binary files /dev/null and b/gifs/Multiple_2D_STVK_implicit_True_fall_8.gif differ
diff --git a/gifs/single_2D_Neohookean_implicit_True.gif b/gifs/single_2D_Neohookean_implicit_True.gif
index 55e7627..f4c43d1 100644
Binary files a/gifs/single_2D_Neohookean_implicit_True.gif and b/gifs/single_2D_Neohookean_implicit_True.gif differ
diff --git a/jacobin.py b/jacobin.py
new file mode 100644
index 0000000..0bb454e
--- /dev/null
+++ b/jacobin.py
@@ -0,0 +1,45 @@
+import numpy as np
+
+A = np.array([[5, 2, 1],
+ [-1, 4, 2],
+ [2, -3, 10]])
+bb = np.array([[-12], [20], [3]])
+
+def JacoBinSolver(A, b, iter=100, error=0.001):
+ # Formulate DLU
+ m, n = np.shape(A)
+ D = np.mat(np.zeros((m, n)))
+ L = np.mat(np.zeros((m, n)))
+ U = np.mat(np.zeros((m, n)))
+ for i in range(m):
+ for j in range(n):
+ if i == j:
+ D[i, j] = A[i, j]
+ if i < j:
+ L[i, j] = -A[i, j]
+ if i > j:
+ U[i, j] = -A[i, j]
+
+ b = np.reshape(b,(-1,1))
+ # Initial value
+ x0 = np.array(np.zeros((m, 1)))
+ xk = np.array(np.zeros((m, 1)))
+
+ B = np.dot(D.I, (L + U))
+ f = np.dot(D.I, b)
+
+ iter_time = 1
+ xk = np.dot(B, x0) + f
+ while(np.linalg.norm((xk - x0)) >= error):
+ iter_time += 1
+ x0 = xk
+ xk = np.dot(B, xk) + f
+ if iter_time > iter:
+ break
+ result = np.squeeze(xk.A)
+ return result
+
+
+if __name__ == "__main__":
+ aa = JacoBinSolver(A,bb)
+ print(aa)
\ No newline at end of file
diff --git a/main_multiple_2d.py b/main_multiple_2d.py
index b8aac66..0594e94 100644
--- a/main_multiple_2d.py
+++ b/main_multiple_2d.py
@@ -27,7 +27,7 @@
help='Empty voxels:[],[2,3,6,7,10,11,14,15],[2,3,6,7]')
# Parameters of FEM
- parser.add_argument('--mode', type=str, default="fall",
+ parser.add_argument('--mode', type=str, default="bend",
help='Mode: bend,fall')
parser.add_argument('--model', type=int, default=3,
help='Constitutive model, 0:Linear, 1:STVK, 2:Co-rotated, 3: Neohookean')
@@ -41,7 +41,7 @@
help='Iteration')
parser.add_argument('--mass', type=float, default=1.0,
help='Mass of the point')
- parser.add_argument('--implict', action="store_true",
+ parser.add_argument('--implict', default=True,
help='Implict Euler Method, for STVK and Neohookean')
args = parser.parse_args()
diff --git a/main_single_2d.py b/main_single_2d.py
index de5eb04..d48e3f6 100644
--- a/main_single_2d.py
+++ b/main_single_2d.py
@@ -37,7 +37,7 @@
help='Add gravity')
parser.add_argument('--fix', type=bool, default=True,
help='Fix a point on the wall')
- parser.add_argument('--implict', action='store_true',
+ parser.add_argument('--implict', default=True,
help='Implict Euler Method, for STVK and Neohookean')
args = parser.parse_args()