├── .vscode ├── launch.json └── settings.json ├── AbaqusSR_images └── Full_NR_scheme.png ├── Algorithm_images ├── Dijkstra.png ├── dp.png └── greedy.png ├── CG_images ├── 3d_rotation.png ├── Mview.png ├── crossRec.jpg ├── cross_product.png ├── matrix_tf1.png ├── orthogonal_pj.png ├── perspective_pj0.png ├── perspective_pj1.png ├── perspective_pj2.png ├── perspective_pj3.png ├── perspective_pj4.png ├── projection.png ├── rabbit.jpg ├── rabbit2.jpg ├── triProj.png ├── view1.png ├── view2.png └── view3.png ├── CUDA_images ├── block&warp.png ├── cuda_grid_block_thread.pdf ├── fermi.png ├── grid_block_thread.png ├── hardware&software.png └── thread_divergence.png ├── LICENSE ├── MPM_images ├── APIC_pg_cubic.png ├── APIC_pg_linear.png ├── APIC_pg_quadratic.png ├── MLS-MPM-cutting.png ├── MLS-MPM_paperFan.png ├── PICkernel.png ├── YDlogo.avi ├── YDlogo.gif ├── apic.png ├── cancel.png ├── cut.gif ├── cutSolid.png ├── diff_cutting.png ├── drawing.svg ├── drawingLinear.svg ├── drawing_cubic.svg ├── elastic.png ├── elastoplastic.png ├── fan.gif ├── frame_00011.png ├── frame_00054.png ├── frame_00189.png ├── hybridEL.png ├── mls_mpm.png ├── nodalForce1.png ├── nodalForce2.png ├── penalty_force.png ├── pic_vs_apic.py ├── svd.png └── weakcomp.png ├── Notes_AbaqusSubroutine.md ├── Notes_Algorithm.md ├── Notes_CG.md ├── Notes_CUDA.md ├── Notes_MPM.md ├── Notes_SPH.md ├── Notes_Taichi.md ├── README.md ├── SPH_images ├── DFSPH.gif ├── DFSPH1.png ├── DFSPH_CDsolver.png ├── DFSPH_DFsolver.png ├── DFSPH_overall_Alg.png ├── IISPH_alg.png ├── NS-equations.png ├── PICkernel.png ├── SPH_NeighborList.png ├── WCSPH_0500.png ├── WCSPH_10000.png ├── WCSPH_4000.png ├── WCSPH_6500.png ├── WCSPH_PCISPH.png ├── mesh_gear.PNG ├── ms_5.png ├── ms_6.png ├── particle_gear.PNG ├── sim_gear.png ├── sphH.png ├── sph_preprocess1.png ├── sph_preprocess2.png └── sph_preprocess3.png ├── Taichi_images ├── 10algs.png ├── APIC_pg_cubic.png ├── APIC_pg_linear.png ├── APIC_pg_quadratic.png ├── DFSPH.gif ├── DFSPH1.png ├── DFSPH_CDsolver.png ├── DFSPH_DFsolver.png ├── DFSPH_overall_Alg.png ├── IISPH_alg.png ├── MLS-MPM-cutting.png ├── MLS-MPM_paperFan.png ├── NS-equations.png ├── PICkernel.png ├── SPH_NeighborList.png ├── WCSPH_0500.png ├── WCSPH_10000.png ├── WCSPH_4000.png ├── WCSPH_6500.png ├── WCSPH_PCISPH.png ├── YDlogo.avi ├── YDlogo.gif ├── apic.png ├── cancel.png ├── cut.gif ├── cutSolid.png ├── diff_cutting.png ├── drawing.svg ├── drawingLinear.svg ├── drawing_cubic.svg ├── drop.mp4 ├── elastic.png ├── elastoplastic.png ├── fan.gif ├── fmm_summation.png ├── frame_00011.png ├── frame_00054.png ├── frame_00189.png ├── hybridEL.png ├── mls_mpm.png ├── ms_1.png ├── ms_2.png ├── ms_3.png ├── ms_4.png ├── ms_5.png ├── ms_6.png ├── nodalForce1.png ├── nodalForce2.png ├── penalty_force.png ├── pic_vs_apic.py ├── sphH.png ├── sph_preprocess1.png ├── sph_preprocess2.png ├── sph_preprocess3.png ├── svd.png └── weakcomp.png └── codes ├── Markdown_show.md ├── SPH ├── DFSPH_SOLVER.py └── startSolver.py ├── autodiff.py ├── mpm_cutting_rotation.py ├── mpm_cutting_thin.py └── mpm_logo.py /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "g++.exe - 生成和调试活动文件", 9 | "type": "cppdbg", 10 | "request": "launch", 11 | "program": "${fileDirname}\\${fileBasenameNoExtension}.exe", 12 | "args": [], 13 | "stopAtEntry": false, 14 | "cwd": "${fileDirname}", 15 | "environment": [], 16 | "externalConsole": false, 17 | "MIMode": "gdb", 18 | "miDebuggerPath": "D:\\software_install\\MinGW\\mingw64\\bin\\gdb.exe", 19 | "setupCommands": [ 20 | { 21 | "description": "为 gdb 启用整齐打印", 22 | "text": "-enable-pretty-printing", 23 | "ignoreFailures": true 24 | } 25 | ], 26 | "preLaunchTask": "C/C++: g++.exe 生成活动文件" 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.pythonPath": "C:\\Users\\LittleFish\\Anaconda3\\envs\\py37\\python.exe", 3 | "python.formatting.provider": "yapf" 4 | } -------------------------------------------------------------------------------- /AbaqusSR_images/Full_NR_scheme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/AbaqusSR_images/Full_NR_scheme.png -------------------------------------------------------------------------------- /Algorithm_images/Dijkstra.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Algorithm_images/Dijkstra.png -------------------------------------------------------------------------------- /Algorithm_images/dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Algorithm_images/dp.png -------------------------------------------------------------------------------- /Algorithm_images/greedy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Algorithm_images/greedy.png -------------------------------------------------------------------------------- /CG_images/3d_rotation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CG_images/3d_rotation.png -------------------------------------------------------------------------------- /CG_images/Mview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CG_images/Mview.png -------------------------------------------------------------------------------- /CG_images/crossRec.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CG_images/crossRec.jpg -------------------------------------------------------------------------------- /CG_images/cross_product.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CG_images/cross_product.png -------------------------------------------------------------------------------- /CG_images/matrix_tf1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CG_images/matrix_tf1.png -------------------------------------------------------------------------------- /CG_images/orthogonal_pj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CG_images/orthogonal_pj.png -------------------------------------------------------------------------------- /CG_images/perspective_pj0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CG_images/perspective_pj0.png -------------------------------------------------------------------------------- /CG_images/perspective_pj1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CG_images/perspective_pj1.png -------------------------------------------------------------------------------- /CG_images/perspective_pj2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CG_images/perspective_pj2.png -------------------------------------------------------------------------------- /CG_images/perspective_pj3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CG_images/perspective_pj3.png -------------------------------------------------------------------------------- /CG_images/perspective_pj4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CG_images/perspective_pj4.png -------------------------------------------------------------------------------- /CG_images/projection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CG_images/projection.png -------------------------------------------------------------------------------- /CG_images/rabbit.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CG_images/rabbit.jpg -------------------------------------------------------------------------------- /CG_images/rabbit2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CG_images/rabbit2.jpg -------------------------------------------------------------------------------- /CG_images/triProj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CG_images/triProj.png -------------------------------------------------------------------------------- /CG_images/view1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CG_images/view1.png -------------------------------------------------------------------------------- /CG_images/view2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CG_images/view2.png -------------------------------------------------------------------------------- /CG_images/view3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CG_images/view3.png -------------------------------------------------------------------------------- /CUDA_images/block&warp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CUDA_images/block&warp.png -------------------------------------------------------------------------------- /CUDA_images/cuda_grid_block_thread.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CUDA_images/cuda_grid_block_thread.pdf -------------------------------------------------------------------------------- /CUDA_images/fermi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CUDA_images/fermi.png -------------------------------------------------------------------------------- /CUDA_images/grid_block_thread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CUDA_images/grid_block_thread.png -------------------------------------------------------------------------------- /CUDA_images/hardware&software.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CUDA_images/hardware&software.png -------------------------------------------------------------------------------- /CUDA_images/thread_divergence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/CUDA_images/thread_divergence.png -------------------------------------------------------------------------------- /MPM_images/APIC_pg_cubic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/APIC_pg_cubic.png -------------------------------------------------------------------------------- /MPM_images/APIC_pg_linear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/APIC_pg_linear.png -------------------------------------------------------------------------------- /MPM_images/APIC_pg_quadratic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/APIC_pg_quadratic.png -------------------------------------------------------------------------------- /MPM_images/MLS-MPM-cutting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/MLS-MPM-cutting.png -------------------------------------------------------------------------------- /MPM_images/MLS-MPM_paperFan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/MLS-MPM_paperFan.png -------------------------------------------------------------------------------- /MPM_images/PICkernel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/PICkernel.png -------------------------------------------------------------------------------- /MPM_images/YDlogo.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/YDlogo.avi -------------------------------------------------------------------------------- /MPM_images/YDlogo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/YDlogo.gif -------------------------------------------------------------------------------- /MPM_images/apic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/apic.png -------------------------------------------------------------------------------- /MPM_images/cancel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/cancel.png -------------------------------------------------------------------------------- /MPM_images/cut.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/cut.gif -------------------------------------------------------------------------------- /MPM_images/cutSolid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/cutSolid.png -------------------------------------------------------------------------------- /MPM_images/diff_cutting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/diff_cutting.png -------------------------------------------------------------------------------- /MPM_images/drawing.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 42 | 44 | 45 | 47 | image/svg+xml 48 | 50 | 51 | 52 | 53 | 54 | 58 | 65 | 70 | 75 | 82 | 88 | 94 | 100 | 106 | 112 | 118 | 124 | 130 | 136 | 142 | Grid point 153 | Particle 161 | 162 | 163 | -------------------------------------------------------------------------------- /MPM_images/drawingLinear.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 42 | 44 | 45 | 47 | image/svg+xml 48 | 50 | 51 | 52 | 53 | 54 | 58 | 65 | 71 | 77 | 83 | 89 | 95 | Grid point 106 | Particle 114 | 115 | 116 | -------------------------------------------------------------------------------- /MPM_images/drawing_cubic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 42 | 44 | 45 | 47 | image/svg+xml 48 | 50 | 51 | 52 | 53 | 54 | 58 | 65 | 70 | 75 | 81 | 87 | 93 | 99 | 105 | 111 | 117 | 123 | 129 | 135 | Grid point 146 | Particle 156 | 161 | 167 | 173 | 179 | 184 | 190 | 196 | 202 | 208 | 209 | 210 | -------------------------------------------------------------------------------- /MPM_images/elastic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/elastic.png -------------------------------------------------------------------------------- /MPM_images/elastoplastic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/elastoplastic.png -------------------------------------------------------------------------------- /MPM_images/fan.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/fan.gif -------------------------------------------------------------------------------- /MPM_images/frame_00011.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/frame_00011.png -------------------------------------------------------------------------------- /MPM_images/frame_00054.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/frame_00054.png -------------------------------------------------------------------------------- /MPM_images/frame_00189.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/frame_00189.png -------------------------------------------------------------------------------- /MPM_images/hybridEL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/hybridEL.png -------------------------------------------------------------------------------- /MPM_images/mls_mpm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/mls_mpm.png -------------------------------------------------------------------------------- /MPM_images/nodalForce1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/nodalForce1.png -------------------------------------------------------------------------------- /MPM_images/nodalForce2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/nodalForce2.png -------------------------------------------------------------------------------- /MPM_images/penalty_force.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/penalty_force.png -------------------------------------------------------------------------------- /MPM_images/pic_vs_apic.py: -------------------------------------------------------------------------------- 1 | # pic_vs_apic.py 2 | # In this program, initial velocities is given. How to enforce forces? 3 | import taichi as ti 4 | import random 5 | ti.init(arch=ti.gpu) 6 | 7 | dim = 2 8 | n_particles = 8192 9 | # number of grid points along each axis 10 | n_grid = 32 11 | dx = 1 / n_grid 12 | inv_dx = 1 / dx 13 | dt = 2.0e-3 14 | use_apic = False 15 | 16 | # coordinates of particles 17 | x = ti.Vector.field(dim, dtype=ti.f32, shape=n_particles) 18 | # velocities of particles 19 | v = ti.Vector(dim, dt=ti.f32, shape=n_particles) 20 | C = ti.Matrix(dim, dim, dt=ti.f32, shape=n_particles) 21 | grid_v = ti.Vector(dim, dt=ti.f32, shape=(n_grid, n_grid)) 22 | #grid_m = ti.var(dt=ti.f32, shape=(n_grid, n_grid)) 23 | grid_m = ti.field(dtype=ti.f32, shape=(n_grid, n_grid)) 24 | 25 | @ti.func 26 | def clamp_pos(pos): 27 | return ti.Vector([max(min(0.95, pos[0]), 0.05), max(min(0.95, pos[1]), 0.05)]) 28 | 29 | @ti.kernel 30 | def substep_PIC(): 31 | # P2G 32 | for p in x: 33 | # create a local coordinate system, base as the origin 34 | base = (x[p] * inv_dx - 0.5).cast(int) 35 | fx = x[p] * inv_dx - base.cast(float) 36 | # Quadratic B-spline (quadratic kernel) 37 | # assume particle mass is 1. 38 | w = [0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1) ** 2, 0.5 * (fx - 0.5) ** 2] 39 | for i in ti.static(range(3)): 40 | for j in ti.static(range(3)): 41 | offset = ti.Vector([i, j]) 42 | weight = w[i][0] * w[j][1] 43 | grid_v[base + offset] += weight * v[p] 44 | grid_m[base + offset] += weight 45 | # Grid normalization 46 | for i, j in grid_m: 47 | if grid_m[i, j] > 0: 48 | inv_m = 1 / grid_m[i, j] 49 | grid_v[i, j] = inv_m * grid_v[i, j] 50 | # G2P 51 | for p in x: 52 | base = (x[p] * inv_dx - 0.5).cast(int) 53 | fx = x[p] * inv_dx - base.cast(float) 54 | # Quadratic B-spline 55 | w = [ 56 | 0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1.0) ** 2, 0.5 * (fx - 0.5) ** 2 57 | ] 58 | new_v = ti.Vector.zero(ti.f32, 2) 59 | for i in ti.static(range(3)): 60 | for j in ti.static(range(3)): 61 | weight = w[i][0] * w[j][1] 62 | new_v += weight * grid_v[base + ti.Vector([i, j])] 63 | 64 | x[p] = clamp_pos(x[p] + v[p] * dt) 65 | v[p] = new_v 66 | 67 | @ti.kernel 68 | def substep_APIC(): 69 | for p in x: 70 | base = (x[p] * inv_dx - 0.5).cast(int) 71 | fx = x[p] * inv_dx - base.cast(float) 72 | # Quadratic B-spline 73 | w = [0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1) ** 2, 0.5 * (fx - 0.5) ** 2] 74 | affine = C[p] 75 | for i in ti.static(range(3)): 76 | for j in ti.static(range(3)): 77 | offset = ti.Vector([i, j]) 78 | dpos = (offset.cast(float) - fx) * dx 79 | weight = w[i][0] * w[j][1] 80 | grid_v[base + offset] += weight * (v[p] + affine @ dpos) 81 | grid_m[base + offset] += weight 82 | 83 | for i, j in grid_m: 84 | if grid_m[i, j] > 0: 85 | inv_m = 1 / grid_m[i, j] 86 | grid_v[i, j] = inv_m * grid_v[i, j] 87 | 88 | for p in x: 89 | base = (x[p] * inv_dx - 0.5).cast(int) 90 | fx = x[p] * inv_dx - base.cast(float) 91 | # Quadratic B-spline 92 | w = [ 93 | 0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1.0) ** 2, 0.5 * (fx - 0.5) ** 2 94 | ] 95 | new_v = ti.Vector.zero(ti.f32, 2) 96 | new_C = ti.Matrix.zero(ti.f32, 2, 2) 97 | for i in ti.static(range(3)): 98 | for j in ti.static(range(3)): 99 | # the dx in dpos is eliminated in the computation of new_C!! 100 | dpos = ti.Vector([i, j]).cast(float) - fx 101 | g_v = grid_v[base + ti.Vector([i, j])] 102 | weight = w[i][0] * w[j][1] 103 | new_v += weight * g_v 104 | # where is dx^2 ?? only 1 inv_dx is presented here!! 105 | # the other dx is eliminated with that in dpos. 106 | new_C += 4 * weight * g_v.outer_product(dpos) * inv_dx 107 | 108 | x[p] = clamp_pos(x[p] + new_v * dt) 109 | v[p] = new_v 110 | C[p] = new_C 111 | 112 | @ti.kernel 113 | def reset(mode: ti.i32): 114 | for i in range(n_particles): 115 | x[i] = [ti.random() * 0.6 + 0.2, ti.random() * 0.6 + 0.2] 116 | if mode == 0: 117 | v[i] = [1, 0] 118 | elif mode == 1: 119 | v[i] = [x[i][1] - 0.5, 0.5 - x[i][0]] 120 | elif mode == 2: 121 | v[i] = [0, x[i][0] - 0.5] 122 | else: 123 | v[i] = [0, x[i][1] - 0.5] 124 | 125 | reset(1) 126 | 127 | gui = ti.GUI("PIC v.s. APIC", (512, 512)) 128 | for frame in range(2000000): 129 | if gui.get_event(ti.GUI.PRESS): 130 | if gui.event.key == 't': reset(0) 131 | elif gui.event.key == 'r': reset(1) 132 | elif gui.event.key == 's': reset(2) 133 | elif gui.event.key == 'd': reset(3) 134 | elif gui.event.key in [ti.GUI.ESCAPE, ti.GUI.EXIT]: break 135 | elif gui.event.key == 'a': use_apic = not use_apic 136 | for s in range(10): 137 | grid_v.fill([0, 0]) 138 | grid_m.fill(0) 139 | if use_apic: 140 | substep_APIC() 141 | else: 142 | substep_PIC() 143 | scheme = 'APIC' if use_apic else 'PIC' 144 | gui.clear(0x112F41) 145 | gui.text('(D) Reset as dilation', pos=(0.05, 0.25)) 146 | gui.text('(T) Reset as translation', pos=(0.05, 0.2)) 147 | gui.text('(R) Reset as rotation', pos=(0.05, 0.15)) 148 | gui.text('(S) Reset as shearing', pos=(0.05, 0.1)) 149 | gui.text(f'(A) Scheme={scheme}', pos=(0.05, 0.05)) 150 | gui.circles(x.to_numpy(), radius=3, color=0x068587) 151 | gui.show() -------------------------------------------------------------------------------- /MPM_images/svd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/svd.png -------------------------------------------------------------------------------- /MPM_images/weakcomp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/MPM_images/weakcomp.png -------------------------------------------------------------------------------- /Notes_Algorithm.md: -------------------------------------------------------------------------------- 1 | # 递归 2 | 递归性能可能不如循环但是更简洁更容易理解; 3 | 递归会导致内存堆积,可使用尾递归节省内存; 4 | 递归包含两个条件:基线条件(何时退出)+递归条件(何时递归); 5 | 6 | # 排序 7 | ### 选择排序 8 | $O(n^2)$ 9 | ### 快速排序(quicksort) 10 | $O(n\log n)$ 11 | ```py 12 | def quicksort(x): 13 | if len(x) < 2: 14 | return x 15 | else: 16 | mid = x[0] 17 | left = [y for y in x[1:] if y <= mid] 18 | right = [y for y in x[1:] if y > mid] 19 | return quicksort(left) + [mid] + quicksort(right) 20 | ``` 21 | # 栈 22 | 栈有两种操作:压入+弹出; 23 | 所有函数调用均进入调用栈(call stack); 24 | 25 | ```py 26 | def help(): 27 | pass 28 | ``` 29 | 30 | # 广度优先搜索(breadth-first search) 31 | 主要用于解决非加权图(unweighted graph)最短路径搜索问题 32 | (适于使用队列进行存储,FIFO,同级搜索优先) 33 | ```py 34 | from collections import deque 35 | def search(name): 36 | namelist = deque() 37 | namelist += graph[name] 38 | nameChecked = [] 39 | while namelist: 40 | person = namelist.popleft() 41 | if person not in nameChecked: 42 | if isSeller(person): 43 | return True 44 | else: 45 | namelist += graph[person] 46 | nameChecked.append(person) 47 | return False 48 | ``` 49 | 50 | # 迪克斯特拉算法(Dijkstra) 51 | 适用范围: 52 | 不含负权边的加权有向无环图的最短路径,对于含有负权边的加权图可以使用贝尔曼-福德算法(Bellman-Ford)。 53 | 54 | > 负权边会导致当前最便宜的节点可能存在更便宜的路径 55 | 56 | 步骤: 57 | + 找到最“便宜”的节点 58 | + 更新该节点的邻居开销并更新其父节点 59 | + 重复该过程至每个节点均进行该操作 60 | + 计算最终路径 61 | 62 | 实现: 63 | ![](Algorithm_images/Dijkstra.png) 64 | 65 | # 贪婪算法 66 | 不完美但有用的简单算法 (完美往往是优秀的敌人) 67 | 核心思想: 每一步均只考虑当前最大收益的选择 68 | 69 | ![](Algorithm_images/greedy.png) 70 | ```py 71 | # {name: set([items])} 72 | all = {"1": {"a", "b", "c"}, 73 | "2": {"b", "d", "f", "e"}, 74 | "3": {"b"}} 75 | def greedy(all): 76 | target = [] 77 | covered = set() 78 | num = 1 79 | while num: 80 | temp = "" 81 | for item, content in all.items(): 82 | if item not in target: 83 | if temp: 84 | num = len(all[temp]) 85 | else: 86 | num = 0 87 | if len((content | covered) - covered) > num: 88 | temp = item 89 | if temp: 90 | target.append(temp) 91 | covered = covered | all[temp] 92 | 93 | return target 94 | 95 | print(greedy(all)) 96 | ``` 97 | NP完全问题(简称NPC问题,Non-deterministic complete problem) 98 | 对于该类问题,几乎无法找到快速解法,可采用类似于贪婪算法这样的近似算法进行局部最优求解。 99 | 100 | # 动态规划 101 | 将大问题分解为**互相独立**的子问题逐步求解,基于之前结果计算当前方案。 102 | 103 | ![](Algorithm_images/dp.png) 104 | ```py 105 | import numpy as np 106 | pocket = {"water": (3, 10), 107 | "book": (1, 3), 108 | "food": (2, 9), 109 | "jacket": (2, 5), 110 | "camera": (1, 6)} 111 | namemap = ["water", "book", "food", "jacket", "camera"] 112 | capacity = 6 113 | # the possible capacity ranges from 0 to 6 114 | clen = capacity + 1 115 | # only 2 rows are needed 116 | values = np.zeros((2, clen)) 117 | names1 = [[]]*clen 118 | names2 = [[]]*clen 119 | for name in namemap: 120 | for i in range(1, clen): 121 | v1 = values[0, i] 122 | c0, v0 = pocket[name] 123 | names = [name] 124 | if c0 > i: 125 | v0 = 0 126 | c0 = 0 127 | names = [] 128 | v2 = v0 + values[0, i-c0] 129 | if v1 > v2: 130 | names2[i] = names1[i] 131 | values[1, i] = v1 132 | else: 133 | names2[i] = names + names1[i-c0] 134 | values[1, i] = v2 135 | 136 | names1 = names2 137 | names2 = [[]]*clen 138 | values[0] = values[1] 139 | values[1] = np.zeros(clen) 140 | 141 | print("Highest value: {}".format(values[0, -1])) 142 | print("Corresponding items: {}".format(names1[-1])) 143 | ``` 144 | 145 | # K临近算法 (k-nearest neighbor) 146 | 比较笨拙但有效的分类回归算法,通过定义“距离”比较相似性。 147 | 早期的OCR(optical character recognition)以及人脸识别等均应用该算法,重难点在于人工构造特征。目前流行的机器学习算法可以看做是一种隐式的特征自动提取算法,本质思想上与KNN相通。 148 | 149 | # 并行算法 150 | 性能瓶颈: 151 | + 并行性管理开销(reduce 归并函数) 152 | + 负载均衡(map 映射函数) 153 | 154 | # 哈希函数 155 | SHA算法(secure hash algorithm) 156 | 哈希函数可以用于创建散列表,也可以用于比较文件是否相同或相似(相似需要使用局部敏感算法如simhash,即相似内容生成的哈希值也相似,非常适用于大文件比较如文章查重) 157 | 158 | # 线性规划 159 | Simplex算法 -------------------------------------------------------------------------------- /Notes_CG.md: -------------------------------------------------------------------------------- 1 | # Computer graphics (GAMES 101) 2 | ## Transformation 3 | ### Affine transformation (仿射变换) 4 | Scale matrix 5 | $$ 6 | \left[\begin{matrix} x^{'} \\ y^{'} \end{matrix}\right]= 7 | \begin{bmatrix} s_x & 0 \\ 0 & s_y \end{bmatrix} 8 | \begin{bmatrix} x \\ y \end{bmatrix} 9 | $$ 10 | 11 | Reflection matrix 12 | $$ 13 | \begin{bmatrix} x^{'} \\ y^{'} \end{bmatrix}= 14 | \begin{bmatrix} -1 & 0 \\ 0 & -1 \end{bmatrix} 15 | \begin{bmatrix} x \\ y \end{bmatrix} 16 | $$ 17 | 18 | Shear matrix 19 | $$ 20 | \begin{bmatrix} x^{'} \\ y^{'} \end{bmatrix}= 21 | \begin{bmatrix} 1 & a \\ 0 & 1 \end{bmatrix} 22 | \begin{bmatrix} x \\ y \end{bmatrix} 23 | $$ 24 | 25 | Rotation matrix (default counterclockwise) 26 | $$ 27 | \begin{bmatrix} x^{'} \\ y^{'} \end{bmatrix}= 28 | \begin{bmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{bmatrix} 29 | \begin{bmatrix} x \\ y \end{bmatrix} 30 | $$ 31 | 32 | **Linear transforms (combine above)** 33 | $$ 34 | \begin{bmatrix} x^{'} \\ y^{'} \end{bmatrix}= 35 | \begin{bmatrix} a & b \\ c & d \end{bmatrix} 36 | \begin{bmatrix} x \\ y \end{bmatrix} 37 | $$ 38 | 39 | What about translation? 40 | **Affine transformation (仿射变换: linear map + translation)** 41 | $$ 42 | \begin{bmatrix} x^{'} \\ y^{'} \end{bmatrix}= 43 | \begin{bmatrix} a & b \\ c & d \end{bmatrix} 44 | \begin{bmatrix} x \\ y \end{bmatrix}+ 45 | \begin{bmatrix} t_x \\ t_y \end{bmatrix} 46 | $$ 47 | This cannot be representated in matrix form! 48 | Thus we have homogeneous coordinates to unify all of them. 49 | 50 | ### Homogeneous coordinates (齐次坐标) 51 | Add w-coordinate besides x and y. 52 | 2D point = $(x,y,1)^T$ 53 | 2D vector = $(x,y,0)^T$ 54 | 55 | Additionally, we define: 56 | $$ 57 | \left(\begin{matrix} 58 | x \\ y \\ w 59 | \end{matrix}\right)\text{is the 2D point} 60 | \left(\begin{matrix} 61 | \frac{x}{w} \\ \frac{y}{w} \\ 1 62 | \end{matrix}\right), w \neq 0 63 | $$ 64 | These definitions are consistent with the following: 65 | * vector + vector = vector (0 + 0 = 0) 66 | * point - point = vector (1 - 1 = 0) 67 | * point + vector = point (1 + 0 = 1) 68 | * point + point = point (1 + 1 = 2 => 2/2 = 1) 69 | 70 | Compared with affine transformation, with homogeneous coordinates we now have: 71 | $$ 72 | \left(\begin{matrix} 73 | x^{'}\\y^{'}\\1 74 | \end{matrix}\right)= 75 | \left(\begin{matrix} 76 | a & b & t_x \\ c & d & t_y \\ 0 & 0 & 1 77 | \end{matrix}\right) \cdot 78 | \left(\begin{matrix} 79 | x\\y\\1 80 | \end{matrix}\right) 81 | $$ 82 | Scale matrix 83 | $$ 84 | \mathbf{S}(s_x, s_y) = 85 | \left(\begin{matrix} s_x & 0 & 0 \\ 0 & s_y & 0 \\ 0 & 0 & 1 \end{matrix}\right) 86 | $$ 87 | Rotation matrix 88 | $$ 89 | \mathbf{R}(\alpha) = 90 | \left(\begin{matrix} \cos\alpha & -\sin\alpha & 0 \\ \sin\alpha & \cos\alpha & 0 \\ 0 & 0 & 1 \end{matrix}\right) 91 | $$ 92 | Translation matrix 93 | $$ 94 | \mathbf{T}(t_x, t_y) = 95 | \left(\begin{matrix} 1 & 0 & t_x \\ 0 & 1 & t_y \\ 0 & 0 & 1 \end{matrix}\right) 96 | $$ 97 | 98 | ### Composing/Decomposing transformation 99 | Transform ordering matters! 100 | Matrix multiplication is not commutative. 101 | $$ 102 | R_{45} \cdot T_{(1,0)} \neq T_{(1,0)} \cdot R_{45} 103 | $$ 104 | Rotation after translation is different from translation after rotation. 105 | ![](CG_images/matrix_tf1.png) 106 | For this example, we want to rotate this shape around the corner. We can first translate it to the origin, rotate it and the translate it back. (Decomposing) 107 | **Note:** The origin is the reference point of the rotation matrix. 108 | 109 | ### 3D transformations 110 | 3D point = $(x,y,z,1)^T$ 111 | 3D vector = $(x,y,z,0)^T$ 112 | In general, $(x,y,z,w)(w\neq0)$ is the 3D point => $(x/w,y/w,z/w)$ 113 | Affine transformation: 114 | $$ 115 | \left(\begin{matrix}x^{'} \\ y^{'} \\ z^{'} \\ 1 116 | \end{matrix}\right)= 117 | \left(\begin{matrix} 118 | a & b & c & t_x \\ d & e & f & t_y \\ g & 119 | h & i & t_z \\ 0 & 0 & 0 & 1 120 | \end{matrix} \right) \cdot 121 | \left(\begin{matrix}x \\ y \\ z \\ 1 122 | \end{matrix}\right) 123 | $$ 124 | 125 | Scale 126 | $$ 127 | \mathbf{S}(s_x, s_y, s_z) = 128 | \left(\begin{matrix} s_x & 0 & 0 & 0\\ 0 & s_y & 0 & 0\\ 0 & 0 & s_z & 0\\ 0 & 0 & 0 & 1\end{matrix}\right) 129 | $$ 130 | Translation 131 | $$ 132 | \mathbf{T}(t_x, t_y, t_z) = 133 | \left(\begin{matrix} 1 & 0 & 0 & t_x\\ 0 & 1 & 0 & t_y\\ 0 & 0 & 1 & t_z\\ 0 & 0 & 0 & 1\end{matrix}\right) 134 | $$ 135 | Rotation around x-, y-, z-axis 136 | ![](CG_images/3d_rotation.png) 137 | **Note:** $\mathbf{R_y(\alpha)}$ is different! 138 | 139 | Rotation around axis $\mathbf{n}$ by angle $\alpha$ 140 | **Rodrigues' Rotation Formula** 141 | $$ 142 | \mathbf{R}(\mathbf{n},\alpha)=\cos(\alpha)\mathbf{I}+(1-\cos(\alpha))\mathbf{n}\mathbf{n}^T+\sin(\alpha) 143 | \begin{pmatrix} 144 | 0 & -n_z & n_y\\ n_z & 0 & -n_x\\ -n_y & n_x & 0 145 | \end{pmatrix} 146 | $$ 147 | This formula only applies for an axis with the origin as the starting point of the axis $\mathbf{n}$, for other axes we can translate, rotate and then translate. 148 | 149 | 四元数(quaternions)???主要用于旋转插值的处理,未详细展开 150 | $Q=a + b \rm i + c \rm j + d \rm k$ 151 | i,j,k为三个虚部,分别表示x轴正向到y轴正向,z轴正向到x轴正向,y轴正向到z轴正向的旋转 152 | 153 | 154 | ## Transformation Cont. 155 | For rotation matrix 156 | $$ 157 | R_\theta = \left(\begin{matrix}\cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{matrix}\right) 158 | $$ 159 | $$ 160 | R_{-\theta} = \left(\begin{matrix}\cos\theta & \sin\theta \\ -\sin\theta & \cos\theta \end{matrix}\right) = R^T_\theta 161 | $$ 162 | Thus we have 163 | $$ 164 | \begin{aligned} 165 | &R_{-\theta} \cdot R_\theta = I \Rightarrow R_{-\theta} = R^{-1}_\theta \\ &\Rightarrow R^T_\theta=R^{-1}_\theta 166 | \end{aligned} 167 | $$ 168 | Rotation matrix is an orthogonal matrix! 169 | 170 | ### Viewing transformation 171 | Consider how to take a photo 172 | + Find a good place and arrange people (**Model** transformation) 173 | + Find a good angle for the camera (**View** transformation) 174 | + Cheese! (**Projection** transformation) 175 | 176 | Thus we have **MVP** transformation! 177 | Model + View = Model/View = View/Camera transformation 178 | And the total viewing tranformation thus contains: 179 | + View/Camera transformation 180 | + Projection transformation 181 | + Orthographic projection(正交投影) 182 | + Perspective projection(透视投影) 183 | 184 | #### View/Camera transformation 185 | 186 | 187 | Procedures: 188 | 1. Define the camera 189 | ![](CG_images/view1.png) 190 | -Position $\vec{e}$ 191 | -Look-at/gaze direction $\hat g$ 192 | -Up direction $\hat t$ 193 | 194 | This defines a coordinate. 195 | 196 | 2. Transform the camera by $M_{view}$ 197 | Key observation: 198 | The photo will be the same if the camera and all objects move together. 199 | Thus we have 200 | ![](CG_images/view2.png) 201 | ![](CG_images/view3.png) 202 | ![](CG_images/Mview.png) 203 | Here we consider the inverse rotation $R^{-1}_{view}$ rather than the rotation itself. 204 | eg. rotation from X axis->$(1,0,0,0)^T$ to $(\hat g \times \hat t)$ axis->$(x_{\hat g\times\hat t},y_{\hat g\times\hat t},z_{\hat g\times\hat t},0)^T$, we have 205 | $(x_{\hat g\times\hat t},y_{\hat g\times\hat t},z_{\hat g\times\hat t},0)^T = R^{-1}_{view} \cdot (1,0,0,0)^T$, 206 | this satisfies the rotation law thus this is indeed the rotation matrix. 207 | 208 | As we have already proved, the rotaion matrix is an orthogonal matrix. 209 | $R^{-1}_{view} = R^T_{view}$ 210 | Thus $R_{view}$ can be easily obtained. 211 | 妙哉!! 212 | 213 | #### Projection transformation 214 | ![](CG_images/projection.png) 215 | ##### Othographic projection 216 | ![](CG_images/orthogonal_pj.png) 217 | Transform a selected cuboid to the canonical one from [-1,-1,-1] to [1,1,1]. 218 | Here we use right hand coords, but in openGL it uses left hand coordis. 219 | ##### Perspective projection 220 | ![](CG_images/perspective_pj0.png) 221 | ![](CG_images/perspective_pj1.png) 222 | ![](CG_images/perspective_pj2.png) 223 | ![](CG_images/perspective_pj3.png) 224 | ![](CG_images/perspective_pj4.png) 225 | 226 | Still not clear. 227 | What are n and f exactly? 228 | Ans: n is the distance between origin and the near surface and f is that between origin and far surface. 229 | What is on earth perspective projection? 230 | Why transform to a canonical cuboid in the end??? 231 | 232 | What is the change of the point inside the frustum in z direction? nearer or farther?? 233 | 234 | #### Canonical cube to screen 235 | 236 | ### Rasterization (光栅化) 237 | #### Sampling (采样) 238 | Determine whether a point is inside a triangle. 239 | ![](CG_images/cross_product.png) 240 | $\overrightarrow{AB}\times\overrightarrow{AP}\qquad\overrightarrow{BC}\times\overrightarrow{BP}\qquad\overrightarrow{CA}\times\overrightarrow{CP}$ 241 | 如果以上三项同号,说明点P同时在三条边的左侧/右侧,即点P在$\Delta ABC$内部,否则即在外部。 242 | 243 | 平面上的三角形光栅化可以先划出包围盒bounding box,在此范围内对各点用该方法进行判断。 244 | 245 | #### Anti-aliasing (抗锯齿) 246 | 247 | ## Animation 248 | 249 | -------------------------------------------------------------------------------- /Notes_CUDA.md: -------------------------------------------------------------------------------- 1 | # CUDA NOTES 2 | 3 | ## CUDA Language 4 | \_\_global\_\_: 主机(host,CPU)调用,设备(device,GPU)执行; 5 | \_\_device\_\_: 设备调用,设备执行; 6 | \_\_host\_\_: 主机调用,主机执行; 7 | 8 | cuda内存管理: 9 | cudaMalloc(); 10 | cudaMemcpy(); 11 | cudaMemset(); 12 | cudaFree(); 13 | 14 | ## Architecture 15 | ### CUDA architecture (software) 16 | CUDA线程管理层级: 17 | Grid $\rightarrow$ Block $\rightarrow$ Thread 18 | gridDim.x/y/z: 当前线程所在grid所包含的block在三个方向的数量; 19 | blcokDim.x/y/z: 当前线程所在block所包含的thread在三个方向的数量; 20 | blcokIdx.x/y/z: 当前线程所在block的index; 21 | threadIdx.x/y/z: 当前线程在所在blcok内部的相对index; 22 | 23 | kernel_name<<>>(argument list) 24 | 25 | ![](CUDA_images/grid_block_thread.png) 26 | 27 | ### Mapping between GPU hardware and CUDA software 28 | ![](CUDA_images/hardware&software.png) 29 | Hardware GPU: 30 | + Streaming processor(SP): 31 | SP为流处理器,也被称为CUDA core,单个SP对应单个线程thread,为GPU计算的基本单位。 32 | + Streaming multiprocessors(SM): 33 | SM为流式多处理器,由多个SP以及共享内存、寄存器等组成,为基本的完整计算单元,GPU架构即围绕SM的扩展阵列搭建,通过复制SM实现GPU硬件并行。 34 | 单个SM可以支持执行多个block,分配到SM的block只能在该SM上执行而不能重分配到其他SM。一个SM上同一个block内部的thread进行线程级别并行,在同一线程内,指令利用指令级并行将单个线程处理成流水线。从而单个SM可以支持数以百计的thread并发运行。 35 | 36 | Software CUDA: 37 | + Thread 38 | + Block 39 | + Grid 40 | + Warp: 41 | 线程束,一般设备的线程束数量为32(硬件设计决定),每个block中的线程分为若干线程束执行,因而block大小应为线程束数量的整数倍,否则会存在线程束中的线程浪费(warp中的空线程不执行有意义计算但仍然消耗资源)。 42 | warp是GPU调度和运行的基本单元,同一个warp中的所有thread均执行相同的指令。单一SM可以分配多个block,并行多个线程,但从机器角度这些thread并不会同时执行,一个warp需要占用一整个SM运行,在某一时刻SM上只执行一个warp,多个warps轮流进入SM进行计算,由SM上的硬件warp scheduler进行调度。 43 | 44 | > Question: 45 | > 如果每个SM同一时刻只能执行一个warp,那么一个SM包含成百上千个cuda core有什么意义?不是很浪费吗? 46 | 47 | ### SIMT vs SIMD 48 | SIMT和SIMD为不同的并行结构。 49 | + SIMD(single instruction multiple data) 50 | CPU为SIMD架构,即相同指令广播给多个执行单元,每个单元必须执行该指令。 51 | + SIMT(single instruction multiple thread) 52 | GPU为SIMT架构,比SIMD更灵活但效率稍低。同样将相同指令广播给多个执行单元,但每个单元(thread)可选择执行与不执行,相对而言各个thread有一定独立性。 53 | > SIMT包含以下SIMD不具有的特性: 54 | >+ 每个线程有自己的指令地址计数器 55 | >+ 每个线程有自己的寄存器状态 56 | >+ 每个线程有自己的独立执行路径 57 | 58 | ### Fermi architecture 59 | ![](CUDA_images/fermi.png) 60 | Fermi架构是第一个面向通用计算的完整GPU架构,之后的架构均在此基础上发展。 61 | 62 | ## Warp execution 63 | ### 线程束(warp)和线程块(block) 64 | block为逻辑概念,用于编程。 65 | warp偏硬件概念,是SM中基本的执行单元。 66 | 多个block会分配到一个SM上,其中单一block会根据warp大小(一般为32)再分为多个warp,一个warp在SM上根据SIMT执行计算。 67 | ![](CUDA_images/block&warp.png) 68 | 69 | --- 70 | block划分的warp数量应向上取整,即线程束为不可分最小分配单位,允许存在空线程但会消耗资源所以最好block为warpsize的整数倍。 71 | $$\rm WarpsPerBlock=ceil\left(\frac{ThreadsPerBlock}{WarpSize(default:32)}\right)$$ 72 | 73 | --- 74 | block,thread可以为一维、二维、三维,仅为了便于编程处理不同维度数据,硬件层面仅存在一维概念。 75 | 核函数中各个线程的全局id计算如下: 76 | + block(1D) & thread(1D): 77 | tid = threadIdx.x + blockIdx.x * blockDim.x 78 | + block(2D) & thread(2D) 79 | ix = threadIdx.x + blockIdx.x * blockDim.x 80 | iy = threadIdx.y + blockIdx.y * blockDim.y 81 | tid = iy * blockDim.x * gridDim.x + ix 82 | + ... 83 | 实际情况中可能存在无效线程,此时kernel function需要传入数据的具体维度,应具体情况具体分析。 84 | 85 | ### 线程束分化 86 | 同一个线程束(warp)中的线程执行不同的指令,称为线程束分化。 87 | SIMT要求同一warp执行相同指令,而存在判断语句时会存在不同分支,二者不矛盾的关键在于所有分支顺序执行,不满足条件的thread在其他满足条件的thread执行该分支时处于等待状态,如图所示。 88 | ![](CUDA_images/thread_divergence.png) 89 | 90 | 线程束分化主要由逻辑判断的引入导致,会严重影响执行效率,故核函数中应尽量减少判断分支。在分支不可避免时解决方案为**避免同一个线程束内的线程分化**。 91 | 以32为基本单位将相同分支的线程组成同一线程束可以有效提升性能,但是往往会打乱数据顺序需要重新整理。实际上对于一般的分化编译器可以进行默认优化进行规避,但对于稍复杂情况需要特别设计。 92 | 93 | 94 | -------------------------------------------------------------------------------- /Notes_MPM.md: -------------------------------------------------------------------------------- 1 | # Material Point Method 2 | 3 | 4 | 5 | 6 | - [Particle-in-cell (PIC/APIC/FLIP)](#particle-in-cell-picapicflip) 7 | - [Interpolation function (kernel)](#interpolation-function-kernel) 8 | - [Material Point Method (MPM)](#material-point-method-mpm) 9 | - [Classical MPM](#classical-mpm) 10 | - [Deformation gradient](#deformation-gradient) 11 | - [Push forward and pull back (lagrangian and eulerian function)](#push-forward-and-pull-back-lagrangian-and-eulerian-function) 12 | - [Constitutive model](#constitutive-model) 13 | - [Governing equations](#governing-equations) 14 | - [Material particles](#material-particles) 15 | - [Discretization](#discretization) 16 | - [Explicit time integration scheme](#explicit-time-integration-scheme) 17 | - [Implicit time integration](#implicit-time-integration) 18 | - [Collison objects](#collison-objects) 19 | - [Lagrangian forces](#lagrangian-forces) 20 | - [MLS-MPM (Moving Least Squares MPM)](#mls-mpm-moving-least-squares-mpm) 21 | - [:ghost: PIC](#ghost-pic) 22 | - [:ghost: APIC](#ghost-apic) 23 | - [:ghost: MLS-MPM](#ghost-mls-mpm) 24 | - [Constitutive Models](#constitutive-models) 25 | - [Elastic solids](#elastic-solids) 26 | - [Weakly compressible fluids](#weakly-compressible-fluids) 27 | - [Elastoplastic solids](#elastoplastic-solids) 28 | - [Singular value decomposition (SVD)](#singular-value-decomposition-svd) 29 | - [Lagrangian forces in MPM](#lagrangian-forces-in-mpm) 30 | - [Introducing Taichi "field"](#introducing-taichi-field) 31 | - [MPM Extension](#mpm-extension) 32 | - [Moving least squares method (MLS)](#moving-least-squares-method-mls) 33 | - [Least squares (LS)](#least-squares-ls) 34 | - [Weighted least squares (WLS)](#weighted-least-squares-wls) 35 | - [Moving least squares (MLS)](#moving-least-squares-mls) 36 | - [CPIC (Compatible PIC)](#cpic-compatible-pic) 37 | - [MPM-DEM Coupling](#mpm-dem-coupling) 38 | 39 | 40 | 41 | 42 | A fluid solver usually has 2 components: 43 | - Advection (evolving the fields) 44 | - Projection (enforcing incompressibility) 45 | 46 | Eulerian grid is good at projection. (the grids are fixed and is suitable for searching for neighbors) 47 | Lagrangian particles are good at advection. (just move the particles) 48 | 49 | Combine them together where lagrangian particles store most of the information while eulerian grids are auxiliary. 50 | 51 | ![](MPM_images/hybridEL.png) 52 | 53 | ### Particle-in-cell (PIC/APIC/FLIP) 54 | Use particles to carry information while grid as the framework. 55 | 56 | P2G (particle to grid): transfer info from particles to grids using kernel functions (scatter). 57 | 58 | G2P (grid to particle): transfer info from grid to particle (gather). [Angular momentum is not conserved.] 59 | 60 | The particles interact with each other through grids. 61 | 62 | $p$ refers to particle and $i$ refers to grid. 63 | 64 | :dog: Energy dissipation (numerical diffusion) is obvious. 65 | DOF is lost during G2P??. 66 | DOFs of particles are lost in P2G=>G2P since typically the number of particles is much more than that of grids. In G2P, particle velocities are totally overwritten from grids thus some information of particles is lost. In FLIP, the particle velocities are incremented rather than overwritten. 67 | 68 | 2 solutions: 69 | - Transfer more information (rotation...): APIC,PolyPIC 70 | **APIC**[affine particle in cell] + bilibili video 71 | **highly recommended for homework** 72 | **PolyPIC**[polynomial particle in cell] 73 | - Transfer the delta: FLIP 74 | **FLIP**[fluid implicit particles] 75 | gather $\Delta$ of the physical quantities rather than themselves. 76 | PIC: $v_p^{t+1}=gather(v_i^{t+1})$ 77 | FLIP: $v_p^{t+1}=v_p^t+gather(v_i^{t+1}-v_i^{t})$ 78 | PIC is dissipative while FLIP is too noisy. 79 | Combine!! $\Rightarrow$ FLIP0.99=FLIP * 0.99+PIC * 0.01 80 | 81 | To know more about **APIC** and its difference with **PIC** and **FLIP**, refer to *An angular momentum conserving affine-particle-in-cell method (2017JCP)*. 82 | **PIC** loses information during the mapping cycle P2G/G2P thus energy dissipation occurs. 83 | **FLIP** transfers incremental information during cycle and preserves each particle's original information to some extent however too much noise occurs. 84 | **APIC** transfers more information like velocity gradient matrix thus the energy dissipation can be avoided to some extent. 85 | 86 | PIC is almost never used in graphics. 87 | APIC is suggested to start with. 88 | 89 | Refer to [pic_vs_apic codes](MPM_images/pic_vs_apic.py) to learn about the difference between PIC and APIC. 90 | 91 | #### Interpolation function (kernel) 92 | There are mainly 3 kinds of interpolation function used in PIC/APIC/MPM. 93 | ![](MPM_images/PICkernel.png) 94 | For both PIC and APIC, information transfer occurs between each particle ($p$) and its surrounding 4(linear)/9(quadratic)/16(cubic) grid points ($i$). In the figures below, each red particle inside intersects with the surrounding blue grid points through the **kernel function**, which is defined on grid points. 95 | **Linear** 96 |
97 | 98 | **Quadratic** 99 |
100 | 101 | **Cubic** 102 |
103 | 104 | 105 | During P2G and G2P cycle, the velocity is kind of smoothed and energy dissipation occurs. 106 | 107 | APIC conserves angular momentum! 108 | **Angular momentum conservation (角动量守恒)** 109 | Angular momentum (角动量): $m\mathbf{r}\times \mathbf{v}$ 110 | Moment (力矩): $\mathbf{r}\times\mathbf{F}$ 111 | 其中$\mathbf{r}$为位置矢量。 112 | 角动量守恒条件:合力矩为0 113 | 根本在于$\mathbf{F}=m\mathbf{a} \Rightarrow \mathbf{r}\times\mathbf{F}=m\mathbf{r}\times\mathbf{a}$ 114 | 如果合力矩为0,则速度保持不变,角动量恒定 115 | 116 | 动量守恒,角动量守恒都源于牛顿第二定律。 117 | 118 | 合力矩和角动量的关系可以类比合力与动量的关系。 119 | 120 | 121 | ### Material Point Method (MPM) 122 | No elements in MPM. 123 | MPM particles => FEM quadrature points (Gaussian points) 124 | MPM equations are derived using weak formulation. 125 | 126 | #### Classical MPM 127 | Refer to [2016 MPM course](https://www.seas.upenn.edu/~cffjiang/research/mpmcourse/mpmcourse.pdf) for details. 128 | 129 | ##### Deformation gradient 130 | $\mathbf{X}$: undeformed space. 131 | $\mathbf{x}$: deformed space. 132 | $\phi(\mathbf{X},t)$: deformation map. 133 | Their relationship is denoted with 134 | $$\mathbf{x}=\phi(\mathbf{X},t)$$ 135 | 136 | For translation: $\mathbf{x}=\mathbf{X}+vt\mathbf{n}$ 137 | where $\mathbf{n}$ is the moving direction. 138 | For rotation: $\mathbf{x}=\mathbf{R}\mathbf{X}+\mathbf{b}$ 139 | where $\mathbf{R}$ is the rotation matrix.(For 2D cases, $\mathbf{R}=\begin{bmatrix} 140 | \cos\theta & -\sin\theta\\ \sin\theta & \cos\theta 141 | \end{bmatrix}$) 142 | 143 | Deformation gradient: 144 | $$\mathbf{F}=\frac{\partial\phi(\mathbf{X},t)}{\partial\mathbf{X}}=\frac{\partial\mathbf{x}(\mathbf{X},t)}{\partial\mathbf{X}}$$ 145 | 146 | $$F_{ij}=\frac{\partial\phi_i}{\partial X_j}=\frac{\partial x_i}{\partial X_j},\quad i,j=1,\dots,d$$ 147 | 148 | For rigid translation: $\mathbf{F}=\mathbf{I}_{d\times d}$. 149 | For rigid rotation: $\mathbf{F}=\mathbf{R}$. 150 | 151 | The determinant of $\mathbf{F}$: 152 | $$J=\det(\mathbf{F})$$ 153 | 154 | This characterizes the infinitesimal volume change and represents the **ratio** of the infinitesimal volume of material in configuration $\Omega^t$ to the original volume in $\Omega^0$. 155 | 156 | + $J=1$ means no volume change during the transformation. For rigid motions (rotations and translations), $J=1$. 157 | + $J>1$ means volume increase. 158 | + $J<1$ means volume decrease. 159 | + $J=0$ means volume becomes 0. In the real world this is impossible while numerically it is possible, eg. the material is so compressed that it becomes a plane or a line or a single volumeless point. 160 | + $J<0$ means the material is inverted. For a 2D triangle, this means one vertex passes through its opposing edge, resulting in negative area. 161 | 162 | 163 | 164 | ##### Push forward and pull back (lagrangian and eulerian function) 165 | ==Definition:== 166 | Push forward $\Rightarrow$ Eulerian (function of $\mathbf{x}$) 167 | $$v(\mathbf{x},t)=V(\phi^{-1}(\mathbf{x},t),t)$$ 168 | 169 | where $v$ is the push forward of $V$. 170 | Pull back $\Rightarrow$ Lagrangian (function of $\mathbf{X}$) 171 | $$V(\mathbf{X},t)=v(\phi(\mathbf{X},t),t)$$ 172 | 173 | where $V$ is the pull back of $v$. 174 | 175 | ==Material derivative:== 176 | For a general Eulerian function $f(\cdot,t)$, 177 | $$\frac{D}{Dt}f(\mathbf{x},t)=\frac{\partial f(\mathbf{x},t)}{\partial t}+\frac{\partial f(\mathbf{x},t)}{\partial x_j}v_j(\mathbf{x},t)$$ 178 | 179 | where Eulerian $\frac{D}{Dt}f(\mathbf{x},t)$ is the push forward of $\frac{\partial F}{\partial t}$ and $F$ is a Lagrangian function. 180 | 181 | ==Volume and area change:== 182 | Volume: 183 | $$v=JdV$$ 184 | 185 | where $J=\det(\mathbf{F})$, $v\Rightarrow x$(Eulerian), $V\Rightarrow X$(Lagrangian). 186 | Based on this we have 187 | $$\int_{B^t}g(\mathbf{x})d\mathbf{x}=\int_{B^0}G(\mathbf{X})J(\mathbf{X},t)d\mathbf{X}$$ 188 | 189 | where $g$ is the push forward of $G$. 190 | 191 | Area: 192 | $$d\mathbf{s}=\mathbf{F}^{-T}Jd\mathbf{S}\quad or\quad \mathbf{n}ds=\mathbf{F}^{-T}J\mathbf{N}dS$$ 193 | 194 | where $s$ and $S$ are tiny areas. 195 | Based on this we have 196 | $$\int_{\partial B^t}h(\mathbf{x},t)\cdot\mathbf{n}(\mathbf{x})ds(\mathbf{x})=\int_{\partial B^0}H(\mathbf{X})\cdot\mathbf{F}^{-T}(\mathbf{X},t)N(\mathbf{X})J(\mathbf{X},t)dS(\mathbf{X})$$ 197 | 198 | 199 | ##### Constitutive model 200 | For **hyperelastic** material: 201 | PK1 stress (First Piola-Kirchoff stress) $\mathbf{P}$ can be derived from 202 | $$\mathbf{P}=\frac{\partial\psi(\mathbf{F})}{\partial\mathbf{F}}$$ 203 | 204 | where $\psi$ is the elastic energy density function (scalar function) and $\mathbf{F}$ is the deformation gradient. 205 | With index notation, 206 | $$P_{ij}=\frac{\partial\psi}{\partial{F_{ij}}}$$ 207 | 208 | The Cauchy stress can be obtained from 209 | $$\mathbf{\sigma}=\frac{1}{J}\mathbf{P}\mathbf{F}^T=\frac{1}{\det(\mathbf{F})}\frac{\partial\psi}{\partial\mathbf{F}}\mathbf{F}^T$$ 210 | 211 | 2 common hyperelastic materials: Neo-Hookean and Fixed Corotated. 212 | Refer to [elastic solids](#elastic-solids). 213 | 214 | ##### Governing equations 215 | Conservation of mass + Conservation of momentum 216 | 217 | > Determinant differentiation rule: 218 | > For an invertible matrix $\mathbf{A}$, 219 | > $$\frac{\partial\det(\mathbf{A})}{\partial \mathbf{A}}=\det(\mathbf{A}) \mathbf{A}^{-T}$$ 220 | > This leads to the commonly used rule: 221 | > $$\frac{\partial\det(\mathbf{F})}{\partial \mathbf{F}}=\det(\mathbf{F}) \mathbf{F}^{-T}$$ 222 | 223 | ==Weak form of force balance== 224 | Mainly based on conservation of momentum. 225 | (Actually momentum theorem rather than conservation). 226 | $$m\Delta\mathbf{v}=\mathbf{F}\Delta t\Leftrightarrow \frac{m\Delta\mathbf{v}}{\Delta t}=\mathbf{F}$$ 227 | Lagrangian view: 228 | $$\int_{\Omega^0}Q_i(\mathbf{X},t)R(\mathbf{X},0)A_i(\mathbf{X},t)d\mathbf{X}=\int_{\partial\Omega^0}Q_iT_ids(\mathbf{X})-\int_{\Omega^0}Q_{i,j}P_{ij}d\mathbf{X}$$ 229 | 230 | Eulerian view: 231 | $$\int_{\Omega^t}q_i(\mathbf{x},t)\rho(\mathbf{x},t)a_i(\mathbf{x},t)d\mathbf{x}=\int_{\partial\Omega^t}q_it_ids(\mathbf{x})-\int_{\Omega^t}q_{i,k}\sigma_{ik}d\mathbf{x}$$ 232 | 233 | Here $i,j,k$ are component index for dimensions, $t_i$ is the $i$ component of boundary force $\mathbf{t}$. 234 | LHS (left-hand side) is some kind of momentum change rate over time while RHS is some kind of net force ignoring the external force. 235 | 236 | ##### Material particles 237 | Momentum and mass are transfered between grid and particle through interpolation function. 238 | Index notation: 239 | Particle $\qquad\Leftrightarrow\qquad$ $p$ 240 | Grid $\qquad\Leftrightarrow\qquad$ $i$ 241 | 242 | ###### Interpolation function 243 | The interpolation function is defined over the Eulerian grid rather than on the material particles like the kernel of SPH particles. 244 | $$w_{ip}=N_\mathbf{i}(\mathbf{x}_p)=N(\frac{1}{h}(x_p-x_i))N(\frac{1}{h}(y_p-y_i))N(\frac{1}{h}(z_p-z_i))$$ 245 | 246 | $$\nabla w_{ip}=\nabla N_{\mathbf{i}}(\mathbf{x}_p)= 247 | \begin{pmatrix} 248 | \frac{1}{h}N'(\frac{1}{h}(x_p-x_i))N(\frac{1}{h}(y_p-y_i))N(\frac{1}{h}(z_p-z_i))\\ 249 | N(\frac{1}{h}(x_p-x_i))\frac{1}{h}N'(\frac{1}{h}(y_p-y_i))N(\frac{1}{h}(z_p-z_i))\\ 250 | N(\frac{1}{h}(x_p-x_i))N(\frac{1}{h}(y_p-y_i))\frac{1}{h}N'(\frac{1}{h}(z_p-z_i))\\ 251 | \end{pmatrix}$$ 252 | 253 | Refer to [interpolation function](#interpolation-function-kernel) for plots of linear/quadratic/cubic functions. 254 | 255 | ###### Lagrangian/Eulerian mass 256 | P2G mass transfer: 257 | $$m_i=\sum_p m_p N_i(\mathbf{x}_p)$$ 258 | 259 | This ensures the conservation of mass through the partition of unity assumption on interpolation function $\sum_i N_i(\mathbf{x}_p)=1$: 260 | $$\sum_i m_i = \sum_i\sum_p m_p N_i(\mathbf{x}_p) = \sum_p m_p \sum_i N_i(\mathbf{x}_p) = \sum_p m_p$$ 261 | 262 | No G2P mass transfer since the particle mass never changes. 263 | ###### Lagrangian/Eulerian momentum 264 | P2G momentum transfer: 265 | $$\begin{aligned} 266 | (m\mathbf{v})_i &= \sum_p m_p \mathbf{v}_p N_i(\mathbf{x}_p)\\ 267 | \mathbf{v}_i &= \frac{(m\mathbf{v})_i}{m_i} 268 | \end{aligned}$$ 269 | 270 | Since $\sum_i m\mathbf{v}_i = \sum_i(m\mathbf{v})_i=\sum_p\sum_i m_p \mathbf{v}_p N_i(\mathbf{x}_p)=\sum_p m_p \mathbf{v}_p$, momentum is conserved in P2G transfer. 271 | 272 | G2P velocity transfer: 273 | Since particle mass keeps unchanged, only velocity is transfered in G2P rather than momentum. 274 | $$\mathbf{v}_p = \sum_i\mathbf{v}_iN_i(\mathbf{x}_p)$$ 275 | 276 | Since $\sum_p m_p\mathbf{v}_p=\sum_p m_p\sum_i\mathbf{v}_iN_i(\mathbf{x}_p) = \sum_i\mathbf{v}_i\sum_pm_pN_i(\mathbf{x}_p)=\sum_i m_i \mathbf{v}_i$, momentum is conserved in G2P transfer. 277 | > Note:pig:: Unlike mass, total momentum keeps changing in the system. This is achieved in Grid operations through introducing impulse. Details will be given later. 278 | 279 | ##### Discretization 280 | In this part, $i,j,k$ denote grid nodes, $\alpha,\beta,\gamma$ denote dimensional components. 281 | For instance, $q_{i\alpha}$ means the $\alpha$ component of the vector quantity $\mathbf{q}$ that is stored at node $i$. 282 | ###### Discrete time 283 | By introducing $a_{\alpha}(\mathbf{x},t^n)=\frac{1}{\Delta t}(v_\alpha^{n+1}(\mathbf{x})-v_\alpha^n(\mathbf{x}))$ into the [weak form governing equation](#governing-equations), we have 284 | $$\begin{aligned} 285 | &\frac{1}{\Delta t}\int_{\Omega^{t^n}} q_\alpha(\mathbf{x},t^n)\rho(\mathbf{x},t^n)(v_\alpha^{n+1}(\mathbf{x})-v_\alpha^n(\mathbf{x}))d\mathbf{x}\\&=\int_{\partial\Omega^{t^n}}q_\alpha(\mathbf{x},t^n)t_\alpha(\mathbf{x},t^n)ds(\mathbf{x})-\int_{\Omega^{t^n}}q_{\alpha,\beta}(\mathbf{x},t^n)\sigma_{\alpha\beta}(\mathbf{x},t^n)d\mathbf{x} 286 | \end{aligned}$$ 287 | 288 | ###### Discrete space 289 | Further discretize the [weak form force balance equation](#discrete-time) over space, we have 290 | $$\frac{((mv)_{i\alpha}^{n+1}-(mv)_{i\alpha}^{n})}{\Delta t}=\int_{\partial\Omega^{t^n}}N_i(\mathbf{x})t_\alpha(\mathbf{x},t^n)ds(\mathbf{x})-\int_{\Omega^{t^n}}N_{i,\beta}(\mathbf{x})\sigma_{\alpha\beta}(\mathbf{x},t^n)d\mathbf{x}$$ 291 | 292 | Assuming we have an estimate of the Cauchy stress $\mathbf{\sigma}_p^n=\mathbf{\sigma}(\mathbf{x}_p^n,t^n)$ at each Lagrangian particle $\mathbf{x}_p^n$, force on the Eulerian grid node $i$ can be written as 293 | $$\int_{\Omega^{t^n}}N_{i,\beta}(\mathbf{x})\sigma_{\alpha\beta}(\mathbf{x},t^n)d\mathbf{x}\approx\sum_p\sigma_{p\,\alpha\beta}^nN_{i,\beta}(\mathbf{x}_p^n)V_p^n$$ 294 | 295 | where $V_p^n$ is the volume particle $p$ occupied at time $t^n$. 296 | 297 | ###### Estimating volume 298 | There are mainly 2 methods to estimate. 299 | + Estimation based on grid density 300 | $$\begin{aligned} 301 | &m_p\approx R(\mathbf{X}_p,0)V_p^0\approx \rho(\mathbf{x}_p^n,t^n)V_p^n\\ 302 | &\rho(\mathbf{x}_p^n,t^n)\approx\sum_i\rho_i^nN_i(\mathbf{x}_p^n)\\ 303 | &\rho_i^n=\frac{m_i^n}{\Delta x^d}\\ 304 | \end{aligned} 305 | $$ 306 | 307 | where $\Delta x$ is the size of each Eulerian grid and $d$ is the dimension. 308 | Since grid density is easy to compute, the volume can be estimated 309 | $$V_p^n\approx\frac{m_p}{\rho(\mathbf{x}_p^n,t^n)}\approx\frac{m_p}{\sum_i\frac{m_i^n}{\Delta x^d}N_i(\mathbf{x}_p^n)}=\frac{m_p\Delta x^d}{\sum_i m_i^n N_i(\mathbf{x}_p^n)}$$ 310 | 311 | + Estimation based on deformation gradient 312 | Typically we have 313 | $$V_p^n \approx J_p^n V_p^0$$ 314 | 315 | where $J_p^n = \det(\mathbf{F}_p^n)$. 316 | 317 | Baed on the second method and substituting Cauchy stress $\boldsymbol{\sigma}$ with $\frac{1}{J}\mathbf{P}\mathbf{F}^T$, the [force on the Eulerian grid node $i$](#discrete-space) can be further rewritten as 318 | $$\sum_p\sigma_{p\,\alpha\beta}^n N_{i,\beta}(\mathbf{x}_p^n)V_p^n=\sum_p\frac{1}{J_p^n}P_{p\,\alpha\gamma}^n F_{p\,\beta\gamma}^n N_{i,\beta}(\mathbf{x}_p^n)V_p^0J_p^n=\sum_p P_{p\,\alpha\gamma}^n F_{p\,\beta\gamma}^n N_{i,\beta}(\mathbf{x}_p^n)V_p^0$$ 319 | 320 | Now the discretized weak form force balance equation can be written as 321 | $$\frac{((mv)_{i\alpha}^{n+1}-(mv)_{i\alpha}^{n})}{\Delta t}=\int_{\partial\Omega^{t^n}}N_i(\mathbf{x})t_\alpha(\mathbf{x},t^n)ds(\mathbf{x})-\sum_p P_{p\,\alpha\gamma}^n F_{p\,\beta\gamma}^n N_{i,\beta}(\mathbf{x}_p^n)V_p^0$$ 322 | 323 | > Note: Different constitutive models are introduced to the scheme by expressing the PK1 stress $\mathbf{P}$ in different ways. 324 | > In computer graphics, **hyperelastic** material is preferred since it has a well defined potential energy $\psi$ and the PK1 stress can be easily computed as $\mathbf{P}=\frac{\partial\psi}{\partial\mathbf{F}}$. 325 | 326 | ###### Deformation gradient evolution 327 | $$\begin{aligned} 328 | &\frac{\partial}{\partial t}\mathbf{F}(\mathbf{X}_p,t^{n+1})\approx\frac{\mathbf{F}_p^{n+1}-\mathbf{F}_p^n}{\Delta t}\\ 329 | &\mathbf{F}_p^{n+1}=\mathbf{F}_p^n+\Delta t \frac{\partial}{\partial t}\mathbf{F}(\mathbf{X}_p,t^{n+1}) 330 | \end{aligned}$$ 331 | 332 | where $\mathbf{F}(\mathbf{X}_p,t^{n+1})$ is simplified as $\mathbf{F}_p^{n+1}$. 333 | Also we have 334 | $$\begin{aligned} 335 | &\frac{\partial}{\partial t}\mathbf{F}(\mathbf{X},t^{n+1})=\frac{\partial\mathbf{V}}{\partial\mathbf{X}}(\mathbf{X},t^{n+1})=\frac{\partial \mathbf{v}^{n+1}(\mathbf{x})}{\partial\mathbf{x}}\mathbf{F}(\mathbf{X},t^n)\\ 336 | &\mathbf{v}^{n+1}(\mathbf{x})=\sum_i \mathbf{v}_i^{n+1}N_i(\mathbf{x})\\ 337 | &\frac{\partial \mathbf{v}^{n+1}(\mathbf{x})}{\partial\mathbf{x}}=\sum_i \mathbf{v}_i^{n+1}(\frac{\partial N_i(\mathbf{x})}{\partial\mathbf{x}})^T 338 | \end{aligned}$$ 339 | 340 | Combining them together we have 341 | $$\mathbf{F}_p^{n+1}=(\mathbf{I}+\Delta t\sum_i \mathbf{v}_i^{n+1}(\frac{\partial N_i(\mathbf{x}_p^n)}{\partial\mathbf{x}})^T)\mathbf{F}_p^n$$ 342 | 343 | Based on this, $\mathbf{F}_p^{n+1}$ can be obtained given $\mathbf{v}_i^{n+1}$ and $\mathbf{F}_p^n$ at each particle. 344 | 345 | ###### Forces as energy gradient 346 | [Force on the Eulerian grid node](#estimating-volume) (derived from weak form governing equation) can also be derived from energy gradient for hyperelastic material. 347 | 348 | ##### Explicit time integration scheme 349 | + Particle to grid (P2G) 350 | + $(m\mathbf{v})_i^{n+1}=\sum_pw_{ip}(m_p\mathbf{v}_p^n+\mathbf{B}_p(\mathbf{D}_p)^{-1}(\mathbf{x}_i-\mathbf{x}_p))$ (**Grid momentum**) 351 | > This is from APIC. 352 | > $$\begin{aligned}\mathbf{C}_p &= \mathbf{B}_p (\mathbf{D}_p)^{-1}\\\mathbf{D}_p &= \sum_i w_{ip} (\mathbf{x}_i-\mathbf{x}_p)(\mathbf{x}_i-\mathbf{x}_p)^T\\ \mathbf{B}_p &= \sum_i w_{ip} \mathbf{v}_i (\mathbf{x}_i-\mathbf{x}_p)^T \end{aligned}$$ 353 | > 354 | > For quadratic kernel, $\mathbf{D}_p=\frac{\Delta x^2}{4}\mathbf{I}$ and $\mathbf{C}_p=\frac{4}{{\Delta x}^2}\sum_i w_{ip} \mathbf{v}_i (\mathbf{x}_i-\mathbf{x}_p)^T$; 355 | > For cubic kernel, $\mathbf{D}_p=\frac{\Delta x^2}{3}\mathbf{I}$ and $\mathbf{C}_p=\frac{3}{{\Delta x}^2}\sum_i w_{ip} \mathbf{v}_i (\mathbf{x}_i-\mathbf{x}_p)^T$; 356 | > For linear kernel, $\mathbf{C}_p=\sum_i\mathbf{v}_i(\frac{\partial N_i}{\partial\mathbf{x}}(\mathbf{x}_p))^T=\sum_i\mathbf{v}_i(\nabla w_{ip})^T$ 357 | + $m_i^{n+1}=\sum_p m_p w_{ip}$ (**Grid mass**) 358 | + Grid operations 359 | + $\hat\mathbf{v}_i^{n+1}=\frac{(m\mathbf{v})_i^{n+1}}{m_i}$ (**Grid velocity**) 360 | + Only label the grid nodes with nonzero masses as solver unknowns. (**Identify grid DOF**) 361 | + $\mathbf{f}_i^n=-\sum_p \mathbf{P}_p^n {\mathbf{F}_p^n}^T \nabla w_{ip}^n V_p^0$ or $\mathbf{f}_i^n=-\sum_p\boldsymbol{\sigma}_p^n \nabla w_{ip}^n V_p^n$ (**Compute grid forces**) 362 | > The 2 formulas can be transferred via $\boldsymbol{\sigma}=\frac{1}{J}\mathbf{P}\mathbf{F}^T$ and $V_p^n=JV_p^0$. 363 | > For hyperelastic material, $\mathbf{P}$ is easily obtained by $\mathbf{P}=\frac{\partial\psi_p}{\partial\mathbf{F}_p}$ thus the 1st formula is used. 364 | + $\mathbf{v}_i^{n+1}=\hat\mathbf{v}_i^{n+1}+\Delta t\frac{\mathbf{f} _i^n}{m_i}$ (**Grid velocity update**) 365 | > Boundary conditions and collision objects are also taken into account in this part. 366 | + Grid to particle (G2P) 367 | + $\mathbf{F}_p^{n+1}=(\mathbf{I}+\Delta t\sum_i \mathbf{v}_i^{n+1}(\nabla w_{ip}^n)^T)\mathbf{F}_p^n$ (**Particle deformation gradient update**) 368 | > Gradient of interpolation function is needed here. $\nabla w_{ip} = \frac{\partial N_i(\mathbf{x}_p)}{\partial\mathbf{x}}$ is a $d$ dimensional vector. 369 | + $\mathbf{D}_p = \sum_i w_{ip} (\mathbf{x}_i-\mathbf{x}_p)(\mathbf{x}_i-\mathbf{x}_p)^T$ and $\mathbf{B}_p = \sum_i w_{ip} \mathbf{v}_i (\mathbf{x}_i-\mathbf{x}_p)^T$ 370 | > Actually this is $\mathbf{C}_p = \mathbf{B}_p (\mathbf{D}_p)^{-1}$ update. 371 | + $\mathbf{v}_p^{n+1}=\sum_i w_{ip}\mathbf{v}_i^{n+1}$ (**Particle velocity update**) 372 | + $\mathbf{x}_p^{n+1}=\mathbf{x}_p^n+\Delta t \mathbf{v}_p^{n+1}$ (**Particle advection**) 373 | 374 | ##### Implicit time integration 375 | The main difference from explicit scheme lies in the **grid velocity update** step. 376 | + In explicit: 377 | $\mathbf{v}_i^{n+1}=\hat\mathbf{v}_i^{n+1}+\Delta t\frac{\mathbf{f} _i(\mathbf{x}_i^n)}{m_i}$ 378 | + In implicit: 379 | $\mathbf{v}_i^{n+1}=\hat\mathbf{v}_i^{n+1}+\Delta t\frac{\mathbf{f} _i(\mathbf{x}_i^{n+1})}{m_i}$ 380 | > Force is implicitly dependent on grid motion thus the grid velocity cannot be updated directly (backward Euler system). 381 | 382 | With the aid of the equation of motion 383 | $$\mathbf{h}(\mathbf{v}^{n+1})=\mathbf{M}\mathbf{v}^{n+1}-\mathbf{M}\mathbf{v}^n-\Delta t\mathbf{f}_i(\mathbf{x}^n+\Delta t\mathbf{v}^{n+1})=\mathbf{0}$$ 384 | 385 | the updated grid velocity can be computed with Newton-Raphson iteration method 386 | $$\mathbf{v}^{(i+1)}=\mathbf{v}^{(i)}-(\frac{\partial\mathbf{h}}{\partial\mathbf{v}}(\mathbf{v}^{(i)}))^{-1}\mathbf{h}(\mathbf{v}^{(i)})$$ 387 | > where $(i)$ denotes the $i$ th iteration step rather than grid node. At each step, $\mathbf{F}_p$ should also be updated. Usually only one iteration step is taken. 388 | 389 | Solving this eqation with NR method is equivalent to minimizing the following objective function: 390 | $$E(\mathbf{v}_i)=\sum_i\frac{1}{2}m_i\|\mathbf{v}_i-\mathbf{v}_i^n\|^2+e(\mathbf{x}_i^n+\Delta t \mathbf{v}_i)$$ 391 | 392 | Transfering the problem to an optimization problem enables a **larger time step**. This can occur only when the forces can be derived from a potential energy function and the details are omitted here. 393 | 394 | ##### Collison objects 395 | The collison is enforced on grid node velocity immediately after forces are applied to grid velocities. 396 | collison detection + relative velocity computation 397 | 398 | ##### Lagrangian forces 399 | $$\mathbf{f}=-\frac{\partial U}{\partial \mathbf{x}}$$ 400 | 401 | where $U$ is the total energy. 402 | 403 | #### MLS-MPM (Moving Least Squares MPM) 404 | Refer to [MLS-MPM](https://www.seas.upenn.edu/~cffjiang/research/mlsmpm/hu2018mlsmpm.pdf) for details. 405 | Using MLS shape function in MPM 406 | Easier to implement than traditional MPM since velocity gradient is approximated with affine matrix. 407 | Based on APIC. 408 | > ti example mpm88/99/128 409 | 410 | $i$ => grid node, $p$ => particle 411 | 412 | ##### :ghost: PIC 413 | + Particle to grid (P2G) 414 | + $(m\mathbf{v})_i^{n+1}=\sum_p w_{ip} m_p \mathbf{v}_p^n$ 415 | + $m_i^{n+1}=\sum_p m_p w_{ip}$ 416 | + Grid operations 417 | + $\mathbf{v}_i^{n+1}=\frac{(m\mathbf{v})_i^{n+1}}{m_i^{n+1}}$ 418 | + Grid to particle (G2P) 419 | + $\mathbf{v}_p^{n+1}=\sum_i w_{ip}\mathbf{v}_i^{n+1}$ 420 | + $\mathbf{x}_p^{n+1}=\mathbf{x}_p^n+\Delta t \mathbf{v}_p^{n+1}$ 421 | 422 | 423 | ##### :ghost: APIC 424 | ![](MPM_images/apic.png) 425 | The main difference lies in the fact that in G2P, more information (velocity gradient matrix $\boldsymbol{C}_p$) is transfered. 426 | ==Particle velocity gradient $C_p$:== the formula of it here is based on **quadratic** B-Spline kernel function. For Cubic or other kernels, the expression is different. 427 | > **How to derive $\mathbf{C}_p$??** 428 | $$ 429 | \begin{aligned} 430 | \mathbf{C}_p &= \mathbf{B}_p (\mathbf{D}_p)^{-1}\\ 431 | \mathbf{D}_p &= \sum_i \omega_{ip} (\mathbf{x}_i-\mathbf{x}_p)(\mathbf{x}_i-\mathbf{x}_p)^T\\ 432 | \mathbf{B}_p &= \sum_i \omega_{ip} \mathbf{v}_i (\mathbf{x}_i-\mathbf{x}_p)^T 433 | \end{aligned} 434 | $$ 435 | > 436 | > Among these equations, $i$ represents grid node and $p$ represents particle. For **quadratic** kernel funciton(interpolation stencil), $\mathbf{D}_p=\frac{\Delta x^2}{4}\mathbf{I}$ and for **cubic**, $\mathbf{D}_p=\frac{\Delta x^2}{3}\mathbf{I}$ where $\Delta x$ is the size of the grid. The detailed derivation is omitted here. 437 | 438 | ==Incompressible:== 常密度假定,即忽略内能变化,能量守恒表现为动能+势能守恒 439 | 440 | ##### :ghost: MLS-MPM 441 | ![](MPM_images/mls_mpm.png) 442 | 443 | > In P2G, $\boldsymbol{P}(\boldsymbol{F}_p^{n+1})=\frac{\partial\boldsymbol{\psi}}{\partial\bold{F}}$ refers to PK1 stress tensor of the specific constitutive model. For hyperelastic models with a well-defined potential energy density function, this is easy to get. 444 | 445 | > For MLS-MPM, the main difficulty lies in P2G where Grid momentum is hard to obtain considering constitutive model. 446 | 447 | > Comparing with traditional MPM, the main contribution is the unification of the affine matrix and velocity gradient. ($\mathbf{C}_p \approx \nabla \mathbf{v}_p$) 448 | 449 | **How to derive grid momentum:** 450 | ![](MPM_images/nodalForce1.png) 451 | ![](MPM_images/nodalForce2.png) 452 | 453 | **How to employ a different material???** 454 | Substitute different forms of PK1 stress $\mathbf{P}(\mathbf{F})$. 455 | 456 | 457 | Enforcing boundary conditions (BC) on grid velocity: 458 | + Sticky: $\boldsymbol{v}_i^{n+1}=\boldsymbol{0}$ 459 | + Slip: $\boldsymbol{v}_i^{n+1}=\hat\boldsymbol{v}_i^{n+1}-\boldsymbol{n}(\boldsymbol{n}^T\hat\boldsymbol{v}_i^{n+1})$ 460 | + Separate: $\boldsymbol{v}_i^{n+1}=\hat\boldsymbol{v}_i^{n+1}-\boldsymbol{n}\cdot\min(\boldsymbol{n}^T\hat\boldsymbol{v}_i^{n+1},0)$ 461 | 462 | > For boundary condition enforcement: 463 | > For PIC/APIC, when applying BC to a cube moving in x direction, the cube composed of particles will be compressed without moving in y direction. 464 | > For MLS-MPM however, the cube will collapse and move in y direction once impeded in x direction. This mainly results from the deformation gradient and constitutive model?? 465 | 466 | #### Constitutive Models 467 | + Fluid: Equation-of-States (EOS) 468 | + Elastoplastic objects (snow, sand etc.): Yield criteria 469 | + PK1 stress ... 470 | 471 | ##### Elastic solids 472 | PK1 stresses of hyperelastic models: 473 | + Neo-Hookean 474 | + (Fixed) Corotated 475 | 476 | ![](MPM_images/elastic.png) 477 | > $\mathbf{F}=\mathbf{R}\mathbf{S}$ is the polar decomposition of $\mathbf{F}$ ($\mathbf{R}$ a rotation matrix and $\mathbf{S}$ symmetric). 478 | > Since $\mathbf{F}=\mathbf{U}\boldsymbol{\Sigma}\mathbf{V}^T=\mathbf{U}\mathbf{V}^T\mathbf{V}\boldsymbol{\Sigma}\mathbf{V}^T$, we can simply get $\mathbf{R}=\mathbf{U}\mathbf{V}^T$ and $\mathbf{S}=\mathbf{V}\boldsymbol{\Sigma}\mathbf{V}^T$. 479 | 480 | For more information, refer to [2016 MPM course](https://www.seas.upenn.edu/~cffjiang/research/mpmcourse/mpmcourse.pdf) given by Jiang etc. 481 | 482 | ##### Weakly compressible fluids 483 | ![](MPM_images/weakcomp.png) 484 | ![](MPM_images/cancel.png) 485 | 486 | 487 | ##### Elastoplastic solids 488 | ![](MPM_images/elastoplastic.png) 489 | We can also refer to snow paper. 490 | 491 | 492 | ##### Singular value decomposition (SVD) 493 | Every real matrix $M_{n\times m}$ can be decomposed into $M_{n\times m}=U_{n\times n}\Sigma_{n\times m}V_{m\times m}^T$ 494 | U,V => rotation 495 | $\Sigma$ => streching 496 | 497 | Diagonal entries $\sigma_{i}=\Sigma_{ii}$ are called singular values. 498 | 499 | ![](MPM_images/svd.png) 500 | 501 | #### Lagrangian forces in MPM 502 | Treat MPM particles as FEM vertices, and use FEM potential energy model. A triangular mesh is needed. 503 | > ti example mpm_lagrangian_forces 504 | 505 | #### Introducing Taichi "field" 506 | New feature in 0.6.22 507 | Use "field" instead of "tensor" since Taichi v0.6.22. 508 | ti.tensor, ti.var are deprecated with "field". 509 | 510 | ti.var => ti.field(dtype=f32, shape=[]) -> a[None] 511 | ti.tensor => ti.field(dtype=f32, shape=[256,256]) 512 | 513 | 514 | "field" refers to global variable. 515 | ti.Vector.field 516 | ti.Matrix.field 517 | 518 | #### MPM Extension 519 | Refer to [MPM course](https://www.seas.upenn.edu/~cffjiang/research/mpmcourse/mpmcourse.pdf) and [MLS-MPM](https://www.seas.upenn.edu/~cffjiang/research/mlsmpm/hu2018mlsmpm.pdf). 520 | 521 | Dirichlet boundary (第一类边界条件): 边界上待求变量值已知 522 | Neumann boundary (第二类边界条件/自然边界条件): 边界上待求变量外法线方向导数确定 523 | 524 | Key contribution: MLS-MPM uses MLS shape functions. 525 | 526 | Signed distance function (SDF): this function is used to perform inside/outside queries. Different shapes usually have different SDFs. 527 | For the SDF of any point, its sign represents the point's relative location and its return value should be the shortest distance between the shape and the given point. 528 | 529 | #### Moving least squares method (MLS) 530 | Refer to [LS-WLS-MLS](https://www.docin.com/p-271196866.html). 531 | To reconstruct a field based on discrete point cloud. 532 | ##### Least squares (LS) 533 | > Global approximation. Each sample point is treated equally. 534 | 535 | Objective function 536 | $$\min_{f\in\prod^d_m}\sum_i \|f(\mathbf{x}_i)-f_i\|^2$$ 537 | 538 | where $d$ refers to dimension, $m$ refers to degree of the polynomial space, $\mathbf{x}_i$ is the sampling points with given function value $f_i$. 539 | $$f(\mathbf{x})=\mathbf{b}(\mathbf{x})^T\mathbf{c}$$ 540 | 541 | The key point is to compute the coefficients vector $\mathbf{c}$. 542 | 543 | ##### Weighted least squares (WLS) 544 | > Global approximation based on local approximation and weighted summation. 545 | 546 | Objective function: 547 | $$\min_{f\in\prod^d_m}\sum_i \theta(\|\bar\mathbf{x}-\mathbf{x}_i\|)\|f(\mathbf{x}_i)-f_i\|^2$$ 548 | 549 | where $\bar\mathbf{x}$ is a given point, $\theta(\|\bar\mathbf{x}-\mathbf{x}_i\|)$ is a weight function centered at $\bar\mathbf{x}$. The output optimal function is 550 | $$f_{\bar\mathbf{x}}(\mathbf{x})=\mathbf{b}(\mathbf{x}-\bar\mathbf{x})^T\mathbf{c}(\bar\mathbf{x})$$ 551 | 552 | This approximates the function at the domain around given point $\bar\mathbf{x}$ and thus is a local approximation. 553 | For totally $n$ sample points with known values, the global approximation can be expressed as 554 | $$f(\mathbf{x}) = \sum_{j=1}^n\varphi_j(\mathbf{x})f_{\bar\mathbf{x}}(\mathbf{x}) = \sum_{j=1}^n\varphi_j(\mathbf{x})\mathbf{b}(\mathbf{x}-\bar\mathbf{x}_j)^T\mathbf{c}(\bar\mathbf{x}_j)$$ 555 | 556 | where $\varphi_j(\mathbf{x})=\frac{\theta_j(\mathbf{x})}{\sum_{k=1}^n\theta_k(\mathbf{x})}$ is the global weight function which ensures Partition of Unity (PU) $\sum_{j=1}^n\varphi_j(\mathbf{x})=1$ at any point $\mathbf{x}$ of the global domain $\Omega$. 557 | 558 | ##### Moving least squares (MLS) 559 | > Local approximation base on WLS. 560 | > The global approximation is not a single function, but **a list of** local approximation functions based on WLS. 561 | 562 | $$f(\mathbf{x})=f_\mathbf{x}(\mathbf{x})$$ 563 | > For each point $\mathbf{x}$, a local WLS approximation centered at $\mathbf{x}$ is implemented to get its function value. As the point **moves** over the entire domain $\Omega$, the global approximation is obtained. 564 | 565 | #### CPIC (Compatible PIC) 566 | CPIC is designed to deal with rigid body cutting (Displacement discontinuity) and two-way rigid body coupling. Refer to [MLS-MPM](https://www.seas.upenn.edu/~cffjiang/research/mlsmpm/hu2018mlsmpm.pdf) for details. 567 | "Compatible": particle and its surrounding grid node at the same side of the the same rigid body. 568 | 569 | 1. Grid-wise colored distance field (CDF) 570 | > Need to capture 571 | $d_i$: valid distance between grid node and rigid surface; 572 | $A_{ir}$: tag denotes whether there is valid distance between grid and rigid surface (=1: yes; =0: no); 573 | $T_{ir}$: tag denotes which side of the rigid surface the gird is on (= +/-). 574 | 2. Particle-wise colored distance field (based on grid CDF) 575 | > Particle penalty force occurs. (not sure, maybe in step 6) 576 | 3. CPIC P2G transfer 577 | > Only the information of compatible particles is transferred to grid. 578 | 4. Grid operation (apply overall BC) 579 | 5. CPIC G2P transfer 580 | > Need to compute ghost velocity for incompatible grid nodes (impulse from rigid body to particle, projection is needed.) 581 | 6. Rigid body advection 582 | > Impulse from particle to rigid body (Two-way coupling is thus achieved.) 583 | 584 | The following is a snapshot of a MLS-MPM [program](mpm_cutting_thin.py) (CPIC) where a block is cut by a thin plane. 585 | > :ghost: Rigid body impulse and penalty force are not considered. 586 | 587 | ![](MPM_images/cutSolid.png) 588 | ![](MPM_images/cut.gif) 589 | 590 | The following is a snapshot of a CPIC [program](mpm_cutting_rotation.py) about a rotating fan. 591 | > :ghost: No penalty force is considered thus some particles can penetrate the blades. 592 | > **Angular momentum theorem** is employed to simulate the rigid body rotation with the accumulated impulse from the particles to the closest rigid bodies. 593 | 594 | ![](MPM_images/frame_00054.png) 595 | ![](MPM_images/fan.gif) 596 | 597 | The rotation fan case in [MLS-MPM paper](https://www.seas.upenn.edu/~cffjiang/research/mlsmpm/hu2018mlsmpm.pdf). 598 | ![](MPM_images/MLS-MPM_paperFan.png) 599 | 600 | 601 | #### MPM-DEM Coupling 602 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Learning_Notes 2 | My notes recorded while learning something new. 3 | Keep learning!! 4 | # :ghost: :ghost: 5 | -------------------------------------------------------------------------------- /SPH_images/DFSPH.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/DFSPH.gif -------------------------------------------------------------------------------- /SPH_images/DFSPH1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/DFSPH1.png -------------------------------------------------------------------------------- /SPH_images/DFSPH_CDsolver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/DFSPH_CDsolver.png -------------------------------------------------------------------------------- /SPH_images/DFSPH_DFsolver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/DFSPH_DFsolver.png -------------------------------------------------------------------------------- /SPH_images/DFSPH_overall_Alg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/DFSPH_overall_Alg.png -------------------------------------------------------------------------------- /SPH_images/IISPH_alg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/IISPH_alg.png -------------------------------------------------------------------------------- /SPH_images/NS-equations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/NS-equations.png -------------------------------------------------------------------------------- /SPH_images/PICkernel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/PICkernel.png -------------------------------------------------------------------------------- /SPH_images/SPH_NeighborList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/SPH_NeighborList.png -------------------------------------------------------------------------------- /SPH_images/WCSPH_0500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/WCSPH_0500.png -------------------------------------------------------------------------------- /SPH_images/WCSPH_10000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/WCSPH_10000.png -------------------------------------------------------------------------------- /SPH_images/WCSPH_4000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/WCSPH_4000.png -------------------------------------------------------------------------------- /SPH_images/WCSPH_6500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/WCSPH_6500.png -------------------------------------------------------------------------------- /SPH_images/WCSPH_PCISPH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/WCSPH_PCISPH.png -------------------------------------------------------------------------------- /SPH_images/mesh_gear.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/mesh_gear.PNG -------------------------------------------------------------------------------- /SPH_images/ms_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/ms_5.png -------------------------------------------------------------------------------- /SPH_images/ms_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/ms_6.png -------------------------------------------------------------------------------- /SPH_images/particle_gear.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/particle_gear.PNG -------------------------------------------------------------------------------- /SPH_images/sim_gear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/sim_gear.png -------------------------------------------------------------------------------- /SPH_images/sphH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/sphH.png -------------------------------------------------------------------------------- /SPH_images/sph_preprocess1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/sph_preprocess1.png -------------------------------------------------------------------------------- /SPH_images/sph_preprocess2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/sph_preprocess2.png -------------------------------------------------------------------------------- /SPH_images/sph_preprocess3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/SPH_images/sph_preprocess3.png -------------------------------------------------------------------------------- /Taichi_images/10algs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/10algs.png -------------------------------------------------------------------------------- /Taichi_images/APIC_pg_cubic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/APIC_pg_cubic.png -------------------------------------------------------------------------------- /Taichi_images/APIC_pg_linear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/APIC_pg_linear.png -------------------------------------------------------------------------------- /Taichi_images/APIC_pg_quadratic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/APIC_pg_quadratic.png -------------------------------------------------------------------------------- /Taichi_images/DFSPH.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/DFSPH.gif -------------------------------------------------------------------------------- /Taichi_images/DFSPH1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/DFSPH1.png -------------------------------------------------------------------------------- /Taichi_images/DFSPH_CDsolver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/DFSPH_CDsolver.png -------------------------------------------------------------------------------- /Taichi_images/DFSPH_DFsolver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/DFSPH_DFsolver.png -------------------------------------------------------------------------------- /Taichi_images/DFSPH_overall_Alg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/DFSPH_overall_Alg.png -------------------------------------------------------------------------------- /Taichi_images/IISPH_alg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/IISPH_alg.png -------------------------------------------------------------------------------- /Taichi_images/MLS-MPM-cutting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/MLS-MPM-cutting.png -------------------------------------------------------------------------------- /Taichi_images/MLS-MPM_paperFan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/MLS-MPM_paperFan.png -------------------------------------------------------------------------------- /Taichi_images/NS-equations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/NS-equations.png -------------------------------------------------------------------------------- /Taichi_images/PICkernel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/PICkernel.png -------------------------------------------------------------------------------- /Taichi_images/SPH_NeighborList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/SPH_NeighborList.png -------------------------------------------------------------------------------- /Taichi_images/WCSPH_0500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/WCSPH_0500.png -------------------------------------------------------------------------------- /Taichi_images/WCSPH_10000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/WCSPH_10000.png -------------------------------------------------------------------------------- /Taichi_images/WCSPH_4000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/WCSPH_4000.png -------------------------------------------------------------------------------- /Taichi_images/WCSPH_6500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/WCSPH_6500.png -------------------------------------------------------------------------------- /Taichi_images/WCSPH_PCISPH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/WCSPH_PCISPH.png -------------------------------------------------------------------------------- /Taichi_images/YDlogo.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/YDlogo.avi -------------------------------------------------------------------------------- /Taichi_images/YDlogo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/YDlogo.gif -------------------------------------------------------------------------------- /Taichi_images/apic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/apic.png -------------------------------------------------------------------------------- /Taichi_images/cancel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/cancel.png -------------------------------------------------------------------------------- /Taichi_images/cut.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/cut.gif -------------------------------------------------------------------------------- /Taichi_images/cutSolid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/cutSolid.png -------------------------------------------------------------------------------- /Taichi_images/diff_cutting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/diff_cutting.png -------------------------------------------------------------------------------- /Taichi_images/drawing.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 42 | 44 | 45 | 47 | image/svg+xml 48 | 50 | 51 | 52 | 53 | 54 | 58 | 65 | 70 | 75 | 82 | 88 | 94 | 100 | 106 | 112 | 118 | 124 | 130 | 136 | 142 | Grid point 153 | Particle 161 | 162 | 163 | -------------------------------------------------------------------------------- /Taichi_images/drawingLinear.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 42 | 44 | 45 | 47 | image/svg+xml 48 | 50 | 51 | 52 | 53 | 54 | 58 | 65 | 71 | 77 | 83 | 89 | 95 | Grid point 106 | Particle 114 | 115 | 116 | -------------------------------------------------------------------------------- /Taichi_images/drawing_cubic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 42 | 44 | 45 | 47 | image/svg+xml 48 | 50 | 51 | 52 | 53 | 54 | 58 | 65 | 70 | 75 | 81 | 87 | 93 | 99 | 105 | 111 | 117 | 123 | 129 | 135 | Grid point 146 | Particle 156 | 161 | 167 | 173 | 179 | 184 | 190 | 196 | 202 | 208 | 209 | 210 | -------------------------------------------------------------------------------- /Taichi_images/drop.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/drop.mp4 -------------------------------------------------------------------------------- /Taichi_images/elastic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/elastic.png -------------------------------------------------------------------------------- /Taichi_images/elastoplastic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/elastoplastic.png -------------------------------------------------------------------------------- /Taichi_images/fan.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/fan.gif -------------------------------------------------------------------------------- /Taichi_images/fmm_summation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/fmm_summation.png -------------------------------------------------------------------------------- /Taichi_images/frame_00011.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/frame_00011.png -------------------------------------------------------------------------------- /Taichi_images/frame_00054.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/frame_00054.png -------------------------------------------------------------------------------- /Taichi_images/frame_00189.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/frame_00189.png -------------------------------------------------------------------------------- /Taichi_images/hybridEL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/hybridEL.png -------------------------------------------------------------------------------- /Taichi_images/mls_mpm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/mls_mpm.png -------------------------------------------------------------------------------- /Taichi_images/ms_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/ms_1.png -------------------------------------------------------------------------------- /Taichi_images/ms_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/ms_2.png -------------------------------------------------------------------------------- /Taichi_images/ms_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/ms_3.png -------------------------------------------------------------------------------- /Taichi_images/ms_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/ms_4.png -------------------------------------------------------------------------------- /Taichi_images/ms_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/ms_5.png -------------------------------------------------------------------------------- /Taichi_images/ms_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/ms_6.png -------------------------------------------------------------------------------- /Taichi_images/nodalForce1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/nodalForce1.png -------------------------------------------------------------------------------- /Taichi_images/nodalForce2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/nodalForce2.png -------------------------------------------------------------------------------- /Taichi_images/penalty_force.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/penalty_force.png -------------------------------------------------------------------------------- /Taichi_images/pic_vs_apic.py: -------------------------------------------------------------------------------- 1 | # pic_vs_apic.py 2 | # In this program, initial velocities is given. How to enforce forces? 3 | import taichi as ti 4 | import random 5 | ti.init(arch=ti.gpu) 6 | 7 | dim = 2 8 | n_particles = 8192 9 | # number of grid points along each axis 10 | n_grid = 32 11 | dx = 1 / n_grid 12 | inv_dx = 1 / dx 13 | dt = 2.0e-3 14 | use_apic = False 15 | 16 | # coordinates of particles 17 | x = ti.Vector.field(dim, dtype=ti.f32, shape=n_particles) 18 | # velocities of particles 19 | v = ti.Vector(dim, dt=ti.f32, shape=n_particles) 20 | C = ti.Matrix(dim, dim, dt=ti.f32, shape=n_particles) 21 | grid_v = ti.Vector(dim, dt=ti.f32, shape=(n_grid, n_grid)) 22 | #grid_m = ti.var(dt=ti.f32, shape=(n_grid, n_grid)) 23 | grid_m = ti.field(dtype=ti.f32, shape=(n_grid, n_grid)) 24 | 25 | @ti.func 26 | def clamp_pos(pos): 27 | return ti.Vector([max(min(0.95, pos[0]), 0.05), max(min(0.95, pos[1]), 0.05)]) 28 | 29 | @ti.kernel 30 | def substep_PIC(): 31 | # P2G 32 | for p in x: 33 | # create a local coordinate system, base as the origin 34 | base = (x[p] * inv_dx - 0.5).cast(int) 35 | fx = x[p] * inv_dx - base.cast(float) 36 | # Quadratic B-spline (quadratic kernel) 37 | # assume particle mass is 1. 38 | w = [0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1) ** 2, 0.5 * (fx - 0.5) ** 2] 39 | for i in ti.static(range(3)): 40 | for j in ti.static(range(3)): 41 | offset = ti.Vector([i, j]) 42 | weight = w[i][0] * w[j][1] 43 | grid_v[base + offset] += weight * v[p] 44 | grid_m[base + offset] += weight 45 | # Grid normalization 46 | for i, j in grid_m: 47 | if grid_m[i, j] > 0: 48 | inv_m = 1 / grid_m[i, j] 49 | grid_v[i, j] = inv_m * grid_v[i, j] 50 | # G2P 51 | for p in x: 52 | base = (x[p] * inv_dx - 0.5).cast(int) 53 | fx = x[p] * inv_dx - base.cast(float) 54 | # Quadratic B-spline 55 | w = [ 56 | 0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1.0) ** 2, 0.5 * (fx - 0.5) ** 2 57 | ] 58 | new_v = ti.Vector.zero(ti.f32, 2) 59 | for i in ti.static(range(3)): 60 | for j in ti.static(range(3)): 61 | weight = w[i][0] * w[j][1] 62 | new_v += weight * grid_v[base + ti.Vector([i, j])] 63 | 64 | x[p] = clamp_pos(x[p] + v[p] * dt) 65 | v[p] = new_v 66 | 67 | @ti.kernel 68 | def substep_APIC(): 69 | for p in x: 70 | base = (x[p] * inv_dx - 0.5).cast(int) 71 | fx = x[p] * inv_dx - base.cast(float) 72 | # Quadratic B-spline 73 | w = [0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1) ** 2, 0.5 * (fx - 0.5) ** 2] 74 | affine = C[p] 75 | for i in ti.static(range(3)): 76 | for j in ti.static(range(3)): 77 | offset = ti.Vector([i, j]) 78 | dpos = (offset.cast(float) - fx) * dx 79 | weight = w[i][0] * w[j][1] 80 | grid_v[base + offset] += weight * (v[p] + affine @ dpos) 81 | grid_m[base + offset] += weight 82 | 83 | for i, j in grid_m: 84 | if grid_m[i, j] > 0: 85 | inv_m = 1 / grid_m[i, j] 86 | grid_v[i, j] = inv_m * grid_v[i, j] 87 | 88 | for p in x: 89 | base = (x[p] * inv_dx - 0.5).cast(int) 90 | fx = x[p] * inv_dx - base.cast(float) 91 | # Quadratic B-spline 92 | w = [ 93 | 0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1.0) ** 2, 0.5 * (fx - 0.5) ** 2 94 | ] 95 | new_v = ti.Vector.zero(ti.f32, 2) 96 | new_C = ti.Matrix.zero(ti.f32, 2, 2) 97 | for i in ti.static(range(3)): 98 | for j in ti.static(range(3)): 99 | # the dx in dpos is eliminated in the computation of new_C!! 100 | dpos = ti.Vector([i, j]).cast(float) - fx 101 | g_v = grid_v[base + ti.Vector([i, j])] 102 | weight = w[i][0] * w[j][1] 103 | new_v += weight * g_v 104 | # where is dx^2 ?? only 1 inv_dx is presented here!! 105 | # the other dx is eliminated with that in dpos. 106 | new_C += 4 * weight * g_v.outer_product(dpos) * inv_dx 107 | 108 | x[p] = clamp_pos(x[p] + new_v * dt) 109 | v[p] = new_v 110 | C[p] = new_C 111 | 112 | @ti.kernel 113 | def reset(mode: ti.i32): 114 | for i in range(n_particles): 115 | x[i] = [ti.random() * 0.6 + 0.2, ti.random() * 0.6 + 0.2] 116 | if mode == 0: 117 | v[i] = [1, 0] 118 | elif mode == 1: 119 | v[i] = [x[i][1] - 0.5, 0.5 - x[i][0]] 120 | elif mode == 2: 121 | v[i] = [0, x[i][0] - 0.5] 122 | else: 123 | v[i] = [0, x[i][1] - 0.5] 124 | 125 | reset(1) 126 | 127 | gui = ti.GUI("PIC v.s. APIC", (512, 512)) 128 | for frame in range(2000000): 129 | if gui.get_event(ti.GUI.PRESS): 130 | if gui.event.key == 't': reset(0) 131 | elif gui.event.key == 'r': reset(1) 132 | elif gui.event.key == 's': reset(2) 133 | elif gui.event.key == 'd': reset(3) 134 | elif gui.event.key in [ti.GUI.ESCAPE, ti.GUI.EXIT]: break 135 | elif gui.event.key == 'a': use_apic = not use_apic 136 | for s in range(10): 137 | grid_v.fill([0, 0]) 138 | grid_m.fill(0) 139 | if use_apic: 140 | substep_APIC() 141 | else: 142 | substep_PIC() 143 | scheme = 'APIC' if use_apic else 'PIC' 144 | gui.clear(0x112F41) 145 | gui.text('(D) Reset as dilation', pos=(0.05, 0.25)) 146 | gui.text('(T) Reset as translation', pos=(0.05, 0.2)) 147 | gui.text('(R) Reset as rotation', pos=(0.05, 0.15)) 148 | gui.text('(S) Reset as shearing', pos=(0.05, 0.1)) 149 | gui.text(f'(A) Scheme={scheme}', pos=(0.05, 0.05)) 150 | gui.circles(x.to_numpy(), radius=3, color=0x068587) 151 | gui.show() -------------------------------------------------------------------------------- /Taichi_images/sphH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/sphH.png -------------------------------------------------------------------------------- /Taichi_images/sph_preprocess1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/sph_preprocess1.png -------------------------------------------------------------------------------- /Taichi_images/sph_preprocess2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/sph_preprocess2.png -------------------------------------------------------------------------------- /Taichi_images/sph_preprocess3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/sph_preprocess3.png -------------------------------------------------------------------------------- /Taichi_images/svd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/svd.png -------------------------------------------------------------------------------- /Taichi_images/weakcomp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhijie-YU/Learning_Notes/f5bdd930a970e6ba6bafc90a317e435fa16f23c2/Taichi_images/weakcomp.png -------------------------------------------------------------------------------- /codes/Markdown_show.md: -------------------------------------------------------------------------------- 1 | # Markdown Introduction 2 | 3 | 4 | 5 | 6 | - [Markdown Introduction](#markdown-introduction) 7 | - [Basic content](#basic-content) 8 | - [Table](#table) 9 | - [Figure](#figure) 10 | - [Formula](#formula) 11 | - [Code](#code) 12 | 13 | 14 | ## Basic content 15 | Hello everyone! 16 | **Hello everyone!** 17 | ==Hello everyone!== 18 | _Are you okay?_ 19 | :dog::pig::frog::eyes::shit: 20 | 微软雅黑字体 21 | 22 | [Markdown documentation](https://shd101wyy.github.io/markdown-preview-enhanced/#/zh-cn/) 23 | [refer to code](#code) 24 | 25 | ## Table 26 | |$\epsilon_{ijk}$|Condition| 27 | |:----|:----| 28 | |$\epsilon_{ijk}=0$|if any two of i,j,k are equal| 29 | |$\epsilon_{ijk}=1$|for an even permutation (eg. 123,231,312)| 30 | |$\epsilon_{ijk}=-1$|for an odd permutation (eg. 132,213,321)| 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
方法说明颜色名称颜色
此处实现方法利用 CSDN-markdown 内嵌 html 语言的优势Hotpinkrgb(240, 248, 255)
借助 table, tr, td 等表格标签的 bgcolor 属性实现背景色设置AntiqueWhitergb(255, 192, 203)
47 | 48 | ## Figure 49 | ![](CG_images/rabbit2.jpg "Rabbit") 50 | 51 |
52 | 53 | 54 | 产品图片 55 | 56 |
57 | 60 |
61 |
rabbit
65 |
66 | 67 | ## Formula 68 | $$ 69 | \begin{Bmatrix} 70 | \sigma_{11}\\ 71 | \sigma_{22}\\ 72 | \sigma_{33}\\ 73 | \sigma_{12}\\ 74 | \sigma_{23}\\ 75 | \sigma_{13}\\ 76 | \end{Bmatrix}= 77 | \begin{bmatrix} 78 | K+\frac{4}{3}G & K-\frac{2}{3}G & K-\frac{2}{3}G & 0 & 0 & 0\\ 79 | K-\frac{2}{3}G & K+\frac{4}{3}G & K-\frac{2}{3}G & 0 & 0 & 0\\ 80 | K-\frac{2}{3}G & K-\frac{2}{3}G & K+\frac{4}{3}G & 0 & 0 & 0\\ 81 | 0 & 0 & 0 & G & 0 & 0\\ 82 | 0 & 0 & 0 & 0 & G & 0\\ 83 | 0 & 0 & 0 & 0 & 0 & G\\ 84 | \end{bmatrix} 85 | \begin{Bmatrix} 86 | \varepsilon_{11}\\ 87 | \varepsilon_{22}\\ 88 | \varepsilon_{33}\\ 89 | 2\varepsilon_{12}\\ 90 | 2\varepsilon_{23}\\ 91 | 2\varepsilon_{13}\\ 92 | \end{Bmatrix} 93 | $$ 94 | 95 | $\alpha$ and \(\beta\) are special letters. 96 | 97 | ## Code 98 | 99 | ```py {cmd="C:\\Users\\LittleFish\\Anaconda3\\envs\\py37\\python.exe"} 100 | # fractal.py 101 | import taichi as ti 102 | ti.init(arch=ti.cpu) 103 | 104 | n=320 105 | pixels = ti.var(dt=ti.f32, shape=(2*n, n)) 106 | 107 | @ti.func 108 | def complex_sqr(z): 109 | return ti.Vector([z[0]**2 - z[1]**2, z[1] * z[0] *2]) 110 | 111 | @ti.kernel 112 | def paint(t: ti.f32): 113 | for i,j in pixels: 114 | c = ti.Vector([-0.8, ti.cos(t) * 0.2]) 115 | z = ti.Vector([i/n - 1, j/n - 0.5]) * 2 116 | iterations = 0 117 | while z.norm() < 20 and iterations < 50: 118 | z = complex_sqr(z) + c 119 | iterations += 1 120 | pixels[i, j] = 1 - iterations * 0.02 121 | 122 | gui = ti.GUI("Julia Set", res=(n * 2, n)) 123 | for i in range(1000000): 124 | paint(i * 0.03) 125 | gui.set_image(pixels) 126 | gui.show() 127 | ``` 128 | 129 | ```py{cmd="C:\\Users\\LittleFish\\Anaconda3\\envs\\py37\\python.exe"} 130 | print("Hello world!!") 131 | ``` -------------------------------------------------------------------------------- /codes/SPH/startSolver.py: -------------------------------------------------------------------------------- 1 | import taichi as ti 2 | from pyevtk.hl import pointsToVTK 3 | import numpy as np 4 | import time 5 | import os 6 | 7 | from DFSPH_SOLVER import SPHSolver 8 | 9 | ti.init(arch=ti.cpu) 10 | 11 | def main(): 12 | dynamic_allocate = False 13 | adaptive_time_step = True 14 | 15 | sim_physical_time = 5.0 16 | max_frame = 50000 17 | 18 | aabb = (0, 0, 0, 5, 5, 8) 19 | dx = 0.1 20 | up, bottom, left, right, front, back = np.array([aabb[5], aabb[2], aabb[0], aabb[3], aabb[1], aabb[4]]) 21 | orgX = aabb[0] 22 | orgY = aabb[1] 23 | orgZ = aabb[2] 24 | sizeX = aabb[3] - aabb[0] 25 | sizeY = aabb[4] - aabb[1] 26 | sizeZ = aabb[5] - aabb[2] 27 | thickness = 0.3 28 | 29 | sph = SPHSolver([up, bottom, left, right, front, back], 30 | alpha=0.30, 31 | dx=dx, 32 | max_time=sim_physical_time, 33 | max_steps=max_frame, 34 | dynamic_allocate=dynamic_allocate, 35 | adaptive_time_step=adaptive_time_step) 36 | 37 | # Add fluid particles 38 | sph.add_cube(lower_corner=[1.5, 1.5, 2], 39 | cube_size=[2, 2, 4], 40 | velocity=[0.0, 0.0, 0.0], 41 | density=[1000], 42 | material=SPHSolver.material_fluid) 43 | 44 | # Add boundary 45 | sph.add_cube(lower_corner=[orgX-thickness, orgY-thickness, orgZ-thickness], 46 | cube_size=[sizeX+2*thickness, sizeY+2*thickness, thickness], 47 | velocity=[0.0, 0.0, 0.0], 48 | density=[1000], 49 | material=SPHSolver.material_bound) 50 | 51 | sph.add_cube(lower_corner=[orgX-thickness, orgY-thickness, sizeZ], 52 | cube_size=[sizeX+2*thickness, sizeY+2*thickness, thickness], 53 | velocity=[0.0, 0.0, 0.0], 54 | density=[1000], 55 | material=SPHSolver.material_bound) 56 | 57 | sph.add_cube(lower_corner=[orgX-thickness, orgY-thickness, orgZ], 58 | cube_size=[sizeX+2*thickness, thickness, sizeZ], 59 | velocity=[0.0, 0.0, 0.0], 60 | density=[1000], 61 | material=SPHSolver.material_bound) 62 | 63 | sph.add_cube(lower_corner=[orgX-thickness, orgY+sizeY, orgZ], 64 | cube_size=[sizeX+2*thickness, thickness, sizeZ], 65 | velocity=[0.0, 0.0, 0.0], 66 | density=[1000], 67 | material=SPHSolver.material_bound) 68 | 69 | sph.add_cube(lower_corner=[orgX-thickness, orgY, orgZ], 70 | cube_size=[thickness, sizeY, sizeZ], 71 | velocity=[0.0, 0.0, 0.0], 72 | density=[1000], 73 | material=SPHSolver.material_bound) 74 | 75 | sph.add_cube(lower_corner=[orgX+sizeX, orgY, orgZ], 76 | cube_size=[thickness, sizeY, sizeZ], 77 | velocity=[0.0, 0.0, 0.0], 78 | density=[1000], 79 | material=SPHSolver.material_bound) 80 | 81 | t = 0.0 82 | frame = 0 83 | total_start = time.process_time() 84 | while frame < max_frame and t < sim_physical_time: 85 | dt = sph.step(frame, t, total_start) 86 | particles = sph.particle_info() 87 | 88 | if frame % 100 == 0: 89 | if 1: 90 | mat = particles["material"] 91 | fluid = [i for i,m in enumerate(mat) if m] 92 | 93 | pos = particles["position"][np.array(fluid)] 94 | vel = particles["velocity"][np.array(fluid)] 95 | 96 | density = particles["density"][np.array(fluid)] 97 | ddensity = particles["d_density"][np.array(fluid)] 98 | pressure = particles["pressure"][np.array(fluid)] 99 | pos_x = copyData(pos[:,0])[np.array(fluid)] 100 | pos_y = copyData(pos[:,1])[np.array(fluid)] 101 | pos_z = copyData(pos[:,2])[np.array(fluid)] 102 | vel_x = copyData(vel[:,0])[np.array(fluid)] 103 | vel_y = copyData(vel[:,1])[np.array(fluid)] 104 | vel_z = copyData(vel[:,2])[np.array(fluid)] 105 | vel = np.linalg.norm(vel, axis=1)[np.array(fluid)] 106 | 107 | pointsToVTK(f'./vtkData/frame_{frame:06d}', pos_x, pos_y, pos_z, 108 | data={"vel_x": vel_x, "vel_y": vel_y, "vel_z": vel_z, "vel": vel, "material": mat, 109 | "density": density, "ddensity": ddensity, "pressure": pressure}) 110 | 111 | frame += 1 112 | t += dt 113 | 114 | print('Finish') 115 | 116 | def copyData(value): 117 | num = value.size 118 | rvalue = np.zeros(num) 119 | for i in range(num): 120 | rvalue[i] = value[i] 121 | return rvalue 122 | 123 | 124 | 125 | if __name__ == '__main__': 126 | main() -------------------------------------------------------------------------------- /codes/autodiff.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | print("hello") 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /codes/mpm_cutting_rotation.py: -------------------------------------------------------------------------------- 1 | import taichi as ti 2 | import numpy as np 3 | import os 4 | import sys 5 | 6 | ti.init(arch=ti.gpu) # Try to run on GPU 7 | quality = 1 # Use a larger value for higher-res simulations 8 | n_particles, n_grid = 10000 * quality ** 2, 128 * quality 9 | dx, inv_dx = 1 / n_grid, float(n_grid) 10 | dt = 1e-4 / quality 11 | p_vol, p_rho = (dx * 0.5)**2, 1 12 | p_mass = p_vol * p_rho 13 | E, nu = 0.1e4, 0.2 # Young's modulus and Poisson's ratio 14 | mu_0, lambda_0 = E / (2 * (1 + nu)), E * nu / ((1+nu) * (1 - 2 * nu)) # Lame parameters 15 | kh = 10 # penalty stiffness parameter 16 | dy = 0.1 # dynamic friction coefficient for rigid surface 17 | x = ti.Vector.field(2, dtype=float, shape=n_particles) # position 18 | v = ti.Vector.field(2, dtype=float, shape=n_particles) # velocity 19 | C = ti.Matrix.field(2, 2, dtype=float, shape=n_particles) # affine velocity field 20 | F = ti.Matrix.field(2, 2, dtype=float, shape=n_particles) # deformation gradient 21 | material = ti.field(dtype=int, shape=n_particles) # material id 22 | Jp = ti.field(dtype=float, shape=n_particles) # plastic deformation 23 | grid_v = ti.Vector.field(2, dtype=float, shape=(n_grid, n_grid)) # grid node momentum/velocity 24 | grid_m = ti.field(dtype=float, shape=(n_grid, n_grid)) # grid node mass 25 | 26 | 27 | gravity = 10 28 | 29 | n_bodies = 5 30 | # num of rigid segments 31 | n_rseg = 100 32 | # location of nodes on the rigid surface 33 | x_r = ti.Vector.field(2, dtype=float, shape=(n_rseg+1,n_bodies)) 34 | # location of rigid particles 35 | x_rp = ti.Vector.field(2, dtype=float, shape=(n_rseg,n_bodies)) 36 | # velocity of the rigid particles 37 | v_rp = ti.Vector.field(2, dtype=float, shape=(n_rseg,n_bodies)) 38 | 39 | x_ls = ti.Vector.field(2, dtype=float, shape=n_bodies) 40 | x_le = ti.Vector.field(2, dtype=float, shape=()) 41 | m_line = ti.field(dtype=float, shape=()) 42 | J_line = ti.field(dtype=float, shape=()) 43 | Mt = ti.field(dtype=float, shape=()) # angular momentum change 44 | omega = ti.field(dtype=float, shape=()) # angular velocity 45 | 46 | grid_d = ti.Vector.field(n_bodies, dtype=float, shape=(n_grid, n_grid)) 47 | grid_A = ti.Vector.field(n_bodies, dtype=int, shape=(n_grid, n_grid)) 48 | grid_T = ti.Vector.field(n_bodies, dtype=int, shape=(n_grid, n_grid)) 49 | # rigid body index closest to grid node 50 | grid_r = ti.field(dtype=ti.i32, shape=(n_grid, n_grid)) 51 | # rigid particle of different bodies index closet to grid node 52 | grid_rp = ti.field(dtype=ti.i32, shape=(n_grid, n_grid, n_bodies)) 53 | 54 | 55 | p_d = ti.Vector.field(n_bodies, dtype=float, shape=n_particles) 56 | p_A = ti.Vector.field(n_bodies, dtype=int, shape=n_particles) 57 | p_T = ti.Vector.field(n_bodies, dtype=int, shape=n_particles) 58 | p_n = ti.Vector.field(2, dtype=float, shape=(n_particles,n_bodies)) 59 | 60 | 61 | @ti.kernel 62 | def substep(): 63 | Mt[None] = 0.0 64 | # CDF 65 | for i,j in grid_A: 66 | for k in ti.static(range(n_bodies)): 67 | grid_A[i,j][k] = 0 68 | grid_T[i,j][k] = 0 69 | grid_d[i,j][k] = -1.0 70 | grid_rp[i,j,k] = -1 71 | grid_r[i,j] = -1 72 | 73 | for k in ti.static(range(n_bodies)): 74 | for p in range(n_rseg): 75 | ba = x_r[p+1,k] - x_r[p,k] 76 | base = (x_rp[p,k] * inv_dx - 0.5).cast(int) 77 | for i, j in ti.static(ti.ndrange(3, 3)): # Loop over 3x3 grid node neighborhood 78 | offset = ti.Vector([i, j]) 79 | pa = (offset + base).cast(float) * dx - x_r[p,k] 80 | h = pa.dot(ba) / (ba.dot(ba)) 81 | 82 | if h <= 1 and h >= 0: 83 | grid_d[base + offset][k] = (pa - h * ba).norm() 84 | grid_A[base + offset][k] = 1 85 | temp = base + offset 86 | grid_rp[temp[0], temp[1], k] = p 87 | cross = pa[0] * ba[1] - pa[1] * ba[0] 88 | #print(grid_d[base + offset]) 89 | if cross > 0: 90 | grid_T[base + offset][k] = 1 91 | else: 92 | grid_T[base + offset][k] = -1 93 | 94 | for i,j in grid_r: 95 | for k in ti.static(range(n_bodies)): 96 | d_min = 0.0 97 | if grid_A[i,j][k] == 1: 98 | if grid_r[i,j] == -1: 99 | d_min = grid_d[i,j][k] 100 | grid_r[i,j] = k 101 | else: 102 | if grid_d[i,j][k] < d_min: 103 | d_min = grid_d[i,j][k] 104 | grid_r[i,j] = k 105 | 106 | for k in ti.static(range(n_bodies)): 107 | for p in x: 108 | p_A[p][k] = 0 109 | p_T[p][k] = 0 110 | p_d[p][k] = 0.0 111 | 112 | base = (x[p] * inv_dx - 0.5).cast(int) 113 | fx = x[p] * inv_dx - base.cast(float) 114 | w = [0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1) ** 2, 0.5 * (fx - 0.5) ** 2] 115 | Tpr = 0.0 116 | for i, j in ti.static(ti.ndrange(3, 3)): # Loop over 3x3 grid node neighborhood 117 | offset = ti.Vector([i, j]) 118 | if grid_A[base + offset][k] == 1: 119 | p_A[p][k] = 1 120 | 121 | weight = w[i][0] * w[j][1] 122 | Tpr += weight * grid_d[base + offset][k] * grid_T[base + offset][k] 123 | if p_A[p][k] == 1: 124 | if Tpr > 0: 125 | p_T[p][k] = 1 126 | else: 127 | p_T[p][k] = -1 128 | p_d[p][k] = abs(Tpr) 129 | #print(p_d[p]) 130 | 131 | for i, j in grid_m: 132 | grid_v[i, j] = [0, 0] 133 | grid_m[i, j] = 0 134 | 135 | # P2G 136 | for p in x: # Particle state update and scatter to grid (P2G) 137 | # p is a scalar 138 | base = (x[p] * inv_dx - 0.5).cast(int) 139 | fx = x[p] * inv_dx - base.cast(float) 140 | # Quadratic kernels [http://mpm.graphics Eqn. 123, with x=fx, fx-1,fx-2] 141 | w = [0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1) ** 2, 0.5 * (fx - 0.5) ** 2] 142 | F[p] = (ti.Matrix.identity(float, 2) + dt * C[p]) @ F[p] # deformation gradient update 143 | #h = ti.exp(10 * (1.0 - Jp[p])) # Hardening coefficient: snow gets harder when compressed 144 | #if material[p] == 1: # jelly, make it softer 145 | # h = 0.5 146 | #mu, la = mu_0 * h, lambda_0 * h 147 | #if material[p] == 0: # liquid 148 | # mu = 0.0 149 | h = 0.5 150 | mu, la = mu_0 * h, lambda_0 * h 151 | mu = 0 152 | U, sig, V = ti.svd(F[p]) 153 | J = 1.0 154 | for d in ti.static(range(2)): 155 | new_sig = sig[d, d] 156 | #if material[p] == 2: # Snow 157 | # new_sig = min(max(sig[d, d], 1 - 2.5e-2), 1 + 4.5e-3) # Plasticity 158 | #Jp[p] *= sig[d, d] / new_sig 159 | #sig[d, d] = new_sig 160 | J *= new_sig 161 | #if material[p] == 0: # Reset deformation gradient to avoid numerical instability 162 | # F[p] = ti.Matrix.identity(float, 2) * ti.sqrt(J) 163 | #elif material[p] == 2: 164 | # F[p] = U @ sig @ V.transpose() # Reconstruct elastic deformation gradient after plasticity 165 | stress = 2 * mu * (F[p] - U @ V.transpose()) @ F[p].transpose() + ti.Matrix.identity(float, 2) * la * J * (J - 1) 166 | stress = (-dt * p_vol * 4 * inv_dx * inv_dx) * stress 167 | affine = stress + p_mass * C[p] 168 | for i, j in ti.static(ti.ndrange(3, 3)): # Loop over 3x3 grid node neighborhood 169 | offset = ti.Vector([i, j]) 170 | flag = 1 171 | # check compatibility 172 | for k in ti.static(range(n_bodies)): 173 | if p_T[p][k] == grid_T[base + offset][k] or p_T[p][k] * grid_T[base + offset][k] == 0: 174 | pass 175 | else: 176 | flag = 0 177 | if flag: 178 | # compatible particle and grid node 179 | dpos = (offset.cast(float) - fx) * dx 180 | weight = w[i][0] * w[j][1] 181 | grid_v[base + offset] += weight * (p_mass * v[p] + affine @ dpos) 182 | grid_m[base + offset] += weight * p_mass 183 | 184 | 185 | # grid operation 186 | for i, j in grid_m: 187 | if grid_m[i, j] > 0: # No need for epsilon here 188 | grid_v[i, j] = (1 / grid_m[i, j]) * grid_v[i, j] # Momentum to velocity 189 | grid_v[i, j][1] -= dt * gravity # gravity 190 | 191 | if j > n_grid - 3 and grid_v[i,j][1] > 0: grid_v[i, j][1] = 0 192 | 193 | if i < 3 and grid_v[i, j][0] < 0: grid_v[i, j][0] = 0 # Boundary conditions 194 | if i > n_grid - 3 and grid_v[i, j][0] > 0: grid_v[i, j][0] = 0 195 | if j < 3 and grid_v[i, j][1] < 0: grid_v[i, j][1] = 0 196 | #if j > n_grid - 3 and grid_v[i, j][1] > 0: grid_v[i, j][1] = 0 197 | 198 | # G2P 199 | for p in x: # grid to particle (G2P) 200 | base = (x[p] * inv_dx - 0.5).cast(int) 201 | fx = x[p] * inv_dx - base.cast(float) 202 | w = [0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1.0) ** 2, 0.5 * (fx - 0.5) ** 2] 203 | new_v = ti.Vector.zero(float, 2) 204 | new_C = ti.Matrix.zero(float, 2, 2) 205 | for i, j in ti.static(ti.ndrange(3, 3)): # loop over 3x3 grid node neighborhood 206 | offset = ti.Vector([i,j]) 207 | g_v = ti.Vector([0.0, 0.0]) 208 | flag = 1 209 | # check compatibility 210 | for k in ti.static(range(n_bodies)): 211 | if p_T[p][k] == grid_T[base + offset][k] or p_T[p][k] * grid_T[base + offset][k] == 0: 212 | pass 213 | else: 214 | flag = 0 215 | if flag == 0: 216 | #slip boundary 217 | #line = ti.Vector([x_le[0]-x_ls[0],x_le[1]-x_ls[1]]).normalized() 218 | #g_v = v[p].dot(line) * line 219 | r_body = grid_r[base + offset] 220 | temp = base + offset 221 | r_id = grid_rp[temp[0], temp[1], r_body] 222 | 223 | #line = ti.Vector([x_r[r_id+1,r_body][0]-x_r[r_id,r_body][0], x_r[r_id+1,r_body][1]-x_r[r_id,r_body][1]]).normalized() 224 | #pa = ti.Vector([x[p][0]-x_r[r_id,r_body][0], x[p][1]-x_r[r_id][1]]) 225 | line = (x_r[r_id+1,r_body] - x_r[r_id,r_body]).normalized() 226 | pa = x[p] - x_r[r_id,r_body] 227 | np = (pa - pa.dot(line) * line).normalized() 228 | sg = (v[p]-v_rp[r_id,r_body]).dot(np) 229 | if sg > 0: 230 | g_v = v[p] 231 | else: 232 | #g_v = v[p].dot(line) * line 233 | vt = (v[p]-v_rp[r_id,r_body]) - sg * np 234 | xi = max(0, vt.norm()+dy*sg) 235 | #g_v = vt.normalized() * xi + v_rp[r_id] + dt * 1 * np 236 | g_v = vt.normalized() * xi + v_rp[r_id,r_body] 237 | 238 | # accumulate angular momentum 239 | rp = x_rp[r_id,r_body] - x_r[n_rseg,r_body] 240 | weight = w[i][0] * w[j][1] 241 | mvp = p_mass * weight * (v[p] - g_v) 242 | Mt += rp[0] * mvp[1] - rp[1] * mvp[0] # cross product for 2D 243 | 244 | else: 245 | g_v = grid_v[base + offset] 246 | 247 | dpos = ti.Vector([i, j]).cast(float) - fx 248 | weight = w[i][0] * w[j][1] 249 | new_v += weight * g_v 250 | new_C += 4 * inv_dx * weight * g_v.outer_product(dpos) 251 | v[p], C[p] = new_v, new_C 252 | x[p] += dt * v[p] # advection 253 | 254 | # rigid body advection 255 | dw = Mt / J_line 256 | omega[None] += dw 257 | 258 | og_Vec = ti.Vector([0.0,0.0,omega]) 259 | for p,body in x_rp: 260 | rp = x_rp[p,body] - x_r[n_rseg,body] 261 | rp_Vec = ti.Vector([rp[0], rp[1], 0.0]) 262 | vrp = og_Vec.cross(rp_Vec) 263 | #print(vrp) 264 | v_rp[p,body] = ti.Vector([vrp[0], vrp[1]]) 265 | 266 | 267 | for p,body in x_rp: 268 | x_rp[p,body] = x_rp[p,body] + dt * v_rp[p,body] 269 | for j in ti.static(range(n_bodies)): 270 | for i in range(n_rseg-1): 271 | x_r[i+1,j] = (x_rp[i,j]+x_rp[i+1,j]) / 2.0 272 | x_r[0,j] = 2 * x_rp[0,j] - x_r[1,j] 273 | x_r[n_rseg,j] = 2 * x_rp[n_rseg-1,j] - x_r[n_rseg-1,j] 274 | # better do not use [-1] as the index 275 | 276 | 277 | @ti.kernel 278 | def getenergy(): 279 | energy = 0.0 280 | #a = ti.Vector([3,4]) 281 | #print(a.norm()) 282 | 283 | for p in x: 284 | energy += 0.5 * v[p].norm_sqr() * p_mass + gravity * x[p].y 285 | print(energy) 286 | 287 | #group_size = n_particles // 3 288 | @ti.kernel 289 | def initialize(): 290 | for i in range(n_particles): 291 | x[i] = [ti.random() * 0.4 + 0.3, ti.random() * 0.6 + 0.3] 292 | #material[i] = i // group_size # 0: fluid 1: jelly 2: snow 293 | v[i] = ti.Matrix([0, 0]) 294 | F[i] = ti.Matrix([[1, 0], [0, 1]]) 295 | Jp[i] = 1 296 | 297 | x_le[None] = [0.7, 0.15] 298 | length = 0.1 299 | pi = 3.1415926 300 | for i in range(n_bodies): 301 | x_ls[i] = [x_le[None][0]+length*ti.cos((1+i*2/n_bodies)*pi), x_le[None][1]+length*ti.sin((1+i*2/n_bodies)*pi)] 302 | 303 | m_line[None] = 0.0002 # mass for each blade 304 | J_line[None] = m_line * length**2 / 3.0 * n_bodies # total J for a fan 305 | omega[None] = -15 # initial angular velocity 306 | 307 | for j in ti.static(range(n_bodies)): 308 | x_r[0,j] = x_ls[j] 309 | for i in range(n_rseg): 310 | x_r[i+1,j] = x_ls[j] + (x_le[None]-x_ls[j]) / n_rseg * (i+1) 311 | x_rp[i,j] = (x_r[i,j] + x_r[i+1,j]) / 2 312 | 313 | 314 | 315 | initialize() 316 | gui = ti.GUI("Taichi MLS-MPM-Fan", res=512, background_color=0x112F41) 317 | #video_manager = ti.VideoManager(output_dir="pic/",framerate=24,automatic_build=False) 318 | frame = 0 319 | 320 | num = 0 321 | flag = 1 322 | while not gui.get_event(ti.GUI.ESCAPE, ti.GUI.EXIT): 323 | for s in range(int(5e-3 // dt)): 324 | if num < 2000: 325 | substep() 326 | else: 327 | flag = 1 328 | substep() 329 | num +=1 330 | if num % 100 == 0: 331 | getenergy() 332 | colors = np.array([0x068587, 0xED553B, 0xEEEEF0], dtype=np.uint32) 333 | gui.circles(x.to_numpy(), radius=1.5, color=colors[material.to_numpy()]) 334 | if flag == 1: 335 | for i in range(n_bodies): 336 | gui.line(x_r.to_numpy()[0,i], x_r.to_numpy()[-1,i], radius=2.2, color=0xFF0000) 337 | #print(x_rp.to_numpy()[-1]) 338 | 339 | 340 | ''' 341 | grid_A_ = grid_A.to_numpy() 342 | grid_T_ = grid_T.to_numpy() 343 | for i in range(grid_A_.shape[0]): 344 | for j in range(grid_A_.shape[1]): 345 | if grid_T_[i, j] == 1: 346 | gui.circle(np.array([i,j])*dx, radius=2, color=0xED553B) 347 | if grid_T_[i, j] == -1: 348 | gui.circle(np.array([i,j])*dx, radius=2, color=0xEEEEF0) 349 | 350 | ''' 351 | x_ = x.to_numpy() 352 | p_A_ = p_A.to_numpy() 353 | p_T_ = p_T.to_numpy() 354 | for i in range(p_A_.shape[1]): 355 | for j in range(p_A_.shape[0]): 356 | if p_T_[j,i] == 1: 357 | gui.circle(x_[j], radius=1.5, color=0xCD00CD) 358 | if p_T_[j,i] == -1: 359 | gui.circle(x_[j], radius=1.5, color=0x436EEE) 360 | 361 | 362 | filename = f'pic_fanRotation/frame_{frame:05d}.png' 363 | gui.show(filename) # Change to gui.show(f'{frame:06d}.png') to write images to disk 364 | gui.show() 365 | frame += 1 366 | 367 | 368 | # ffmpeg -f image2 -r 24 -i frame_%05d.png fan.gif 369 | # ffmpeg -f image2 -r 24 -i frame_%05d.png -vcodec libx264 test.mp4 370 | 371 | -------------------------------------------------------------------------------- /codes/mpm_cutting_thin.py: -------------------------------------------------------------------------------- 1 | import taichi as ti 2 | import numpy as np 3 | import os 4 | import sys 5 | 6 | ti.init(arch=ti.gpu) # Try to run on GPU 7 | quality = 1 # Use a larger value for higher-res simulations 8 | n_particles, n_grid = 10000 * quality ** 2, 128 * quality 9 | dx, inv_dx = 1 / n_grid, float(n_grid) 10 | dt = 1e-4 / quality 11 | p_vol, p_rho = (dx * 0.5)**2, 1 12 | p_mass = p_vol * p_rho 13 | E, nu = 0.1e4, 0.2 # Young's modulus and Poisson's ratio 14 | mu_0, lambda_0 = E / (2 * (1 + nu)), E * nu / ((1+nu) * (1 - 2 * nu)) # Lame parameters 15 | x = ti.Vector.field(2, dtype=float, shape=n_particles) # position 16 | v = ti.Vector.field(2, dtype=float, shape=n_particles) # velocity 17 | C = ti.Matrix.field(2, 2, dtype=float, shape=n_particles) # affine velocity field 18 | F = ti.Matrix.field(2, 2, dtype=float, shape=n_particles) # deformation gradient 19 | material = ti.field(dtype=int, shape=n_particles) # material id 20 | Jp = ti.field(dtype=float, shape=n_particles) # plastic deformation 21 | grid_v = ti.Vector.field(2, dtype=float, shape=(n_grid, n_grid)) # grid node momentum/velocity 22 | grid_m = ti.field(dtype=float, shape=(n_grid, n_grid)) # grid node mass 23 | energy = ti.field(dtype=float, shape=()) 24 | 25 | gravity = 20 26 | # velocity of the rigid surface 27 | r_v = 1 28 | 29 | # num of rigid segments 30 | n_rseg = 100 31 | # location of nodes on the rigid surface 32 | x_r = ti.Vector.field(2, dtype=float, shape=n_rseg+1) 33 | # location of rigid particles 34 | x_rp = ti.Vector.field(2, dtype=float, shape=n_rseg) 35 | x_ls = [0.8, 0.5] 36 | x_le = [1.2, 0.6] 37 | 38 | grid_d = ti.field(dtype=float, shape=(n_grid, n_grid)) 39 | grid_A = ti.field(dtype=int, shape=(n_grid, n_grid)) 40 | grid_T = ti.field(dtype=int, shape=(n_grid, n_grid)) 41 | 42 | p_d = ti.field(dtype=float, shape=n_particles) 43 | p_A = ti.field(dtype=int, shape=n_particles) 44 | p_T = ti.field(dtype=int, shape=n_particles) 45 | p_n = ti.Vector.field(2, dtype=float, shape=n_particles) 46 | 47 | 48 | @ti.kernel 49 | def substep0(): 50 | for i, j in grid_m: 51 | grid_v[i, j] = [0, 0] 52 | grid_m[i, j] = 0 53 | for p in x: # Particle state update and scatter to grid (P2G) 54 | base = (x[p] * inv_dx - 0.5).cast(int) 55 | fx = x[p] * inv_dx - base.cast(float) 56 | # Quadratic kernels [http://mpm.graphics Eqn. 123, with x=fx, fx-1,fx-2] 57 | w = [0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1) ** 2, 0.5 * (fx - 0.5) ** 2] 58 | F[p] = (ti.Matrix.identity(float, 2) + dt * C[p]) @ F[p] # deformation gradient update 59 | #h = ti.exp(10 * (1.0 - Jp[p])) # Hardening coefficient: snow gets harder when compressed 60 | #if material[p] == 1: # jelly, make it softer 61 | # h = 0.5 62 | #mu, la = mu_0 * h, lambda_0 * h 63 | #if material[p] == 0: # liquid 64 | # mu = 0.0 65 | h = 0.5 66 | mu, la = mu_0 * h, lambda_0 * h 67 | U, sig, V = ti.svd(F[p]) 68 | J = 1.0 69 | for d in ti.static(range(2)): 70 | new_sig = sig[d, d] 71 | #if material[p] == 2: # Snow 72 | # new_sig = min(max(sig[d, d], 1 - 2.5e-2), 1 + 4.5e-3) # Plasticity 73 | #Jp[p] *= sig[d, d] / new_sig 74 | #sig[d, d] = new_sig 75 | J *= new_sig 76 | #if material[p] == 0: # Reset deformation gradient to avoid numerical instability 77 | # F[p] = ti.Matrix.identity(float, 2) * ti.sqrt(J) 78 | #elif material[p] == 2: 79 | # F[p] = U @ sig @ V.transpose() # Reconstruct elastic deformation gradient after plasticity 80 | stress = 2 * mu * (F[p] - U @ V.transpose()) @ F[p].transpose() + ti.Matrix.identity(float, 2) * la * J * (J - 1) 81 | stress = (-dt * p_vol * 4 * inv_dx * inv_dx) * stress 82 | affine = stress + p_mass * C[p] 83 | for i, j in ti.static(ti.ndrange(3, 3)): # Loop over 3x3 grid node neighborhood 84 | offset = ti.Vector([i, j]) 85 | dpos = (offset.cast(float) - fx) * dx 86 | weight = w[i][0] * w[j][1] 87 | grid_v[base + offset] += weight * (p_mass * v[p] + affine @ dpos) 88 | grid_m[base + offset] += weight * p_mass 89 | for i, j in grid_m: 90 | if grid_m[i, j] > 0: # No need for epsilon here 91 | grid_v[i, j] = (1 / grid_m[i, j]) * grid_v[i, j] # Momentum to velocity 92 | grid_v[i, j][1] -= dt * gravity # gravity 93 | 94 | if j > n_grid - 1: grid_v[i, j] = [0, 0] 95 | 96 | if i < 3 and grid_v[i, j][0] < 0: grid_v[i, j][0] = 0 # Boundary conditions 97 | if i > n_grid - 3 and grid_v[i, j][0] > 0: grid_v[i, j][0] = 0 98 | if j < 3 and grid_v[i, j][1] < 0: grid_v[i, j][1] = 0 99 | #if j > n_grid - 3 and grid_v[i, j][1] > 0: grid_v[i, j][1] = 0 100 | for p in x: # grid to particle (G2P) 101 | base = (x[p] * inv_dx - 0.5).cast(int) 102 | fx = x[p] * inv_dx - base.cast(float) 103 | w = [0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1.0) ** 2, 0.5 * (fx - 0.5) ** 2] 104 | new_v = ti.Vector.zero(float, 2) 105 | new_C = ti.Matrix.zero(float, 2, 2) 106 | for i, j in ti.static(ti.ndrange(3, 3)): # loop over 3x3 grid node neighborhood 107 | dpos = ti.Vector([i, j]).cast(float) - fx 108 | g_v = grid_v[base + ti.Vector([i, j])] 109 | weight = w[i][0] * w[j][1] 110 | new_v += weight * g_v 111 | new_C += 4 * inv_dx * weight * g_v.outer_product(dpos) 112 | v[p], C[p] = new_v, new_C 113 | x[p] += dt * v[p] # advection 114 | 115 | 116 | 117 | @ti.kernel 118 | def substep(): 119 | line = ti.Vector([x_le[0]-x_ls[0],x_le[1]-x_ls[1]]).normalized() 120 | for p in x_r: 121 | x_r[p] = x_r[p] - line * dt * r_v 122 | for p in x_rp: 123 | x_rp[p] = x_rp[p] - line * dt * r_v 124 | 125 | # CDF 126 | for i,j in grid_A: 127 | grid_A[i,j] = 0 128 | grid_T[i,j] = 0 129 | grid_d[i,j] = 0.0 130 | 131 | for p in x_rp: 132 | ba = x_r[p+1] - x_r[p] 133 | base = (x_rp[p] * inv_dx - 0.5).cast(int) 134 | for i, j in ti.static(ti.ndrange(3, 3)): # Loop over 3x3 grid node neighborhood 135 | offset = ti.Vector([i, j]) 136 | pa = (offset + base).cast(float) * dx - x_r[p] 137 | h = pa.dot(ba) / (ba.dot(ba)) 138 | 139 | if h <= 1 and h >= 0: 140 | grid_d[base + offset] = (pa - h * ba).norm() 141 | grid_A[base + offset] = 1 142 | outer = pa[0] * ba[1] - pa[1] * ba[0] 143 | #print(grid_d[base + offset]) 144 | if outer > 0: 145 | grid_T[base + offset] = 1 146 | else: 147 | grid_T[base + offset] = -1 148 | 149 | for p in x: 150 | p_A[p] = 0 151 | p_T[p] = 0 152 | p_d[p] = 0.0 153 | 154 | base = (x[p] * inv_dx - 0.5).cast(int) 155 | fx = x[p] * inv_dx - base.cast(float) 156 | w = [0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1) ** 2, 0.5 * (fx - 0.5) ** 2] 157 | Tpr = 0.0 158 | for i, j in ti.static(ti.ndrange(3, 3)): # Loop over 3x3 grid node neighborhood 159 | offset = ti.Vector([i, j]) 160 | if grid_A[base + offset] == 1: 161 | p_A[p] = 1 162 | 163 | weight = w[i][0] * w[j][1] 164 | Tpr += weight * grid_d[base + offset] * grid_T[base + offset] 165 | if p_A[p] == 1: 166 | if Tpr > 0: 167 | p_T[p] = 1 168 | else: 169 | p_T[p] = -1 170 | p_d[p] = abs(Tpr) 171 | #print(p_d[p]) 172 | 173 | 174 | 175 | for i, j in grid_m: 176 | grid_v[i, j] = [0, 0] 177 | grid_m[i, j] = 0 178 | 179 | # P2G 180 | for p in x: # Particle state update and scatter to grid (P2G) 181 | # p is a scalar 182 | base = (x[p] * inv_dx - 0.5).cast(int) 183 | fx = x[p] * inv_dx - base.cast(float) 184 | # Quadratic kernels [http://mpm.graphics Eqn. 123, with x=fx, fx-1,fx-2] 185 | w = [0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1) ** 2, 0.5 * (fx - 0.5) ** 2] 186 | F[p] = (ti.Matrix.identity(float, 2) + dt * C[p]) @ F[p] # deformation gradient update 187 | #h = ti.exp(10 * (1.0 - Jp[p])) # Hardening coefficient: snow gets harder when compressed 188 | #if material[p] == 1: # jelly, make it softer 189 | # h = 0.5 190 | #mu, la = mu_0 * h, lambda_0 * h 191 | #if material[p] == 0: # liquid 192 | # mu = 0.0 193 | h = 0.5 194 | mu, la = mu_0 * h, lambda_0 * h 195 | U, sig, V = ti.svd(F[p]) 196 | J = 1.0 197 | for d in ti.static(range(2)): 198 | new_sig = sig[d, d] 199 | #if material[p] == 2: # Snow 200 | # new_sig = min(max(sig[d, d], 1 - 2.5e-2), 1 + 4.5e-3) # Plasticity 201 | #Jp[p] *= sig[d, d] / new_sig 202 | #sig[d, d] = new_sig 203 | J *= new_sig 204 | #if material[p] == 0: # Reset deformation gradient to avoid numerical instability 205 | # F[p] = ti.Matrix.identity(float, 2) * ti.sqrt(J) 206 | #elif material[p] == 2: 207 | # F[p] = U @ sig @ V.transpose() # Reconstruct elastic deformation gradient after plasticity 208 | stress = 2 * mu * (F[p] - U @ V.transpose()) @ F[p].transpose() + ti.Matrix.identity(float, 2) * la * J * (J - 1) 209 | stress = (-dt * p_vol * 4 * inv_dx * inv_dx) * stress 210 | affine = stress + p_mass * C[p] 211 | for i, j in ti.static(ti.ndrange(3, 3)): # Loop over 3x3 grid node neighborhood 212 | offset = ti.Vector([i, j]) 213 | if p_T[p] * grid_T[base + offset] == -1: 214 | #continue 215 | pass 216 | else: 217 | dpos = (offset.cast(float) - fx) * dx 218 | weight = w[i][0] * w[j][1] 219 | grid_v[base + offset] += weight * (p_mass * v[p] + affine @ dpos) 220 | grid_m[base + offset] += weight * p_mass 221 | 222 | 223 | 224 | # grid operation 225 | for i, j in grid_m: 226 | if grid_m[i, j] > 0: # No need for epsilon here 227 | grid_v[i, j] = (1 / grid_m[i, j]) * grid_v[i, j] # Momentum to velocity 228 | grid_v[i, j][1] -= dt * gravity # gravity 229 | 230 | if j > n_grid - 3: grid_v[i, j] = [0, 0] 231 | 232 | if i < 3 and grid_v[i, j][0] < 0: grid_v[i, j][0] = 0 # Boundary conditions 233 | if i > n_grid - 3 and grid_v[i, j][0] > 0: grid_v[i, j][0] = 0 234 | if j < 3 and grid_v[i, j][1] < 0: grid_v[i, j][1] = 0 235 | #if j > n_grid - 3 and grid_v[i, j][1] > 0: grid_v[i, j][1] = 0 236 | 237 | # G2P 238 | for p in x: # grid to particle (G2P) 239 | base = (x[p] * inv_dx - 0.5).cast(int) 240 | fx = x[p] * inv_dx - base.cast(float) 241 | w = [0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1.0) ** 2, 0.5 * (fx - 0.5) ** 2] 242 | new_v = ti.Vector.zero(float, 2) 243 | new_C = ti.Matrix.zero(float, 2, 2) 244 | for i, j in ti.static(ti.ndrange(3, 3)): # loop over 3x3 grid node neighborhood 245 | g_v = ti.Vector([0.0, 0.0]) 246 | if p_T[p] * grid_T[base + ti.Vector([i,j])] == -1: 247 | #slip boundary 248 | #line = ti.Vector([x_le[0]-x_ls[0],x_le[1]-x_ls[1]]).normalized() 249 | #g_v = v[p].dot(line) * line 250 | 251 | line = ti.Vector([x_le[0]-x_ls[0],x_le[1]-x_ls[1]]).normalized() 252 | pa = ti.Vector([x[p][0]-x_ls[0], x[p][1]-x_ls[1]]) 253 | np = (pa - pa.dot(line) * line).normalized() 254 | sg = v[p].dot(np) 255 | if sg > 0: 256 | g_v = v[p] 257 | else: 258 | g_v = v[p].dot(line) * line 259 | 260 | else: 261 | g_v = grid_v[base + ti.Vector([i, j])] 262 | 263 | dpos = ti.Vector([i, j]).cast(float) - fx 264 | weight = w[i][0] * w[j][1] 265 | new_v += weight * g_v 266 | new_C += 4 * inv_dx * weight * g_v.outer_product(dpos) 267 | v[p], C[p] = new_v, new_C 268 | x[p] += dt * v[p] # advection 269 | 270 | @ti.kernel 271 | def getenergy(): 272 | energy = 0.0 273 | #a = ti.Vector([3,4]) 274 | #print(a.norm()) 275 | 276 | for p in x: 277 | energy += 0.5 * v[p].norm_sqr() + gravity * x[p].y 278 | print(energy) 279 | 280 | #group_size = n_particles // 3 281 | @ti.kernel 282 | def initialize(): 283 | for i in range(n_particles): 284 | x[i] = [ti.random() * 0.4 + 0.3, ti.random() * 0.7 + 0.3] 285 | #material[i] = i // group_size # 0: fluid 1: jelly 2: snow 286 | v[i] = ti.Matrix([0, 0]) 287 | F[i] = ti.Matrix([[1, 0], [0, 1]]) 288 | Jp[i] = 1 289 | 290 | 291 | x_r[0] = x_ls 292 | for i in range(n_rseg): 293 | x_r[i+1] = [x_ls[0] + (x_le[0]-x_ls[0]) / n_rseg * (i+1), x_ls[1] + (x_le[1]-x_ls[1]) / n_rseg * (i+1)] 294 | x_rp[i] = (x_r[i] + x_r[i+1]) / 2 295 | #print(i, x_rp[i]) 296 | #print((x_r[i]+x_r[i+1])/2) 297 | 298 | 299 | initialize() 300 | gui = ti.GUI("Taichi MLS-MPM-99", res=512, background_color=0x112F41) 301 | #video_manager = ti.VideoManager(output_dir="pic/",framerate=24,automatic_build=False) 302 | frame = 0 303 | 304 | num = 0 305 | flag = 1 306 | while not gui.get_event(ti.GUI.ESCAPE, ti.GUI.EXIT): 307 | for s in range(int(5e-3 // dt)): 308 | if num < 2000: 309 | substep() 310 | else: 311 | flag = 1 312 | substep() 313 | num +=1 314 | if num % 100 == 0: 315 | getenergy() 316 | colors = np.array([0x068587, 0xED553B, 0xEEEEF0], dtype=np.uint32) 317 | gui.circles(x.to_numpy(), radius=1.5, color=colors[material.to_numpy()]) 318 | if flag == 1: 319 | gui.line(x_r.to_numpy()[0], x_r.to_numpy()[-1], radius=2, color=0xFF0000) 320 | 321 | ''' 322 | grid_A_ = grid_A.to_numpy() 323 | grid_T_ = grid_T.to_numpy() 324 | for i in range(grid_A_.shape[0]): 325 | for j in range(grid_A_.shape[1]): 326 | if grid_T_[i, j] == 1: 327 | gui.circle(np.array([i,j])*dx, radius=2, color=0xED553B) 328 | if grid_T_[i, j] == -1: 329 | gui.circle(np.array([i,j])*dx, radius=2, color=0xEEEEF0) 330 | 331 | 332 | x_ = x.to_numpy() 333 | p_A_ = p_A.to_numpy() 334 | p_T_ = p_T.to_numpy() 335 | for i in range(p_A_.shape[0]): 336 | if p_T_[i] == 1: 337 | #pass 338 | gui.circle(x_[i], radius=2, color=0xCD00CD) 339 | if p_T_[i] == -1: 340 | #pass 341 | gui.circle(x_[i], radius=2, color=0x436EEE) 342 | ''' 343 | 344 | #filename = f'pic/frame_{frame:05d}.png' 345 | #gui.show(filename) # Change to gui.show(f'{frame:06d}.png') to write images to disk 346 | gui.show() 347 | frame += 1 348 | 349 | 350 | # ffmpeg -f image2 -r 24 -i frame_%05d.png test.gif 351 | # ffmpeg -f image2 -r 24 -i frame_%05d.png -vcodec libx264 test.mp4 352 | 353 | -------------------------------------------------------------------------------- /codes/mpm_logo.py: -------------------------------------------------------------------------------- 1 | import taichi as ti 2 | import numpy as np 3 | ti.init(arch=ti.cpu) # Try to run on GPU 4 | quality = 2 # Use a larger value for higher-res simulations 5 | n_particles, n_grid = 9000 * quality ** 2, 128 * quality 6 | dx, inv_dx = 1 / n_grid, float(n_grid) 7 | dt = 1e-4 / quality 8 | p_vol, p_rho = (dx * 0.5)**2, 1 9 | p_mass = p_vol * p_rho 10 | E, nu = 0.1e4, 0.2 # Young's modulus and Poisson's ratio 11 | mu_0, lambda_0 = E / (2 * (1 + nu)), E * nu / ((1+nu) * (1 - 2 * nu)) # Lame parameters 12 | x = ti.Vector.field(2, dtype=float, shape=n_particles) # position 13 | v = ti.Vector.field(2, dtype=float, shape=n_particles) # velocity 14 | C = ti.Matrix.field(2, 2, dtype=float, shape=n_particles) # affine velocity field 15 | F = ti.Matrix.field(2, 2, dtype=float, shape=n_particles) # deformation gradient 16 | material = ti.field(dtype=int, shape=n_particles) # material id 17 | Jp = ti.field(dtype=float, shape=n_particles) # plastic deformation 18 | grid_v = ti.Vector.field(2, dtype=float, shape=(n_grid, n_grid)) # grid node momentum/velocity 19 | grid_m = ti.field(dtype=float, shape=(n_grid, n_grid)) # grid node mass 20 | 21 | grid_g = ti.Vector.field(2, dtype=float, shape=(n_grid, n_grid)) 22 | 23 | @ti.kernel 24 | def substep(): 25 | for i, j in grid_m: 26 | grid_v[i, j] = [0, 0] 27 | grid_m[i, j] = 0 28 | for p in x: # Particle state update and scatter to grid (P2G) 29 | base = (x[p] * inv_dx - 0.5).cast(int) 30 | fx = x[p] * inv_dx - base.cast(float) 31 | # Quadratic kernels [http://mpm.graphics Eqn. 123, with x=fx, fx-1,fx-2] 32 | w = [0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1) ** 2, 0.5 * (fx - 0.5) ** 2] 33 | F[p] = (ti.Matrix.identity(float, 2) + dt * C[p]) @ F[p] # deformation gradient update 34 | h = ti.exp(10 * (1.0 - Jp[p])) # Hardening coefficient: snow gets harder when compressed 35 | if material[p] == 1: # jelly, make it softer 36 | h = 0.3 37 | mu, la = mu_0 * h, lambda_0 * h 38 | if material[p] == 0 or material[p] == 1: # liquid 39 | mu = 0.0 40 | U, sig, V = ti.svd(F[p]) 41 | J = 1.0 42 | for d in ti.static(range(2)): 43 | new_sig = sig[d, d] 44 | if material[p] == 2: # Snow 45 | new_sig = min(max(sig[d, d], 1 - 2.5e-2), 1 + 4.5e-3) # Plasticity 46 | Jp[p] *= sig[d, d] / new_sig 47 | sig[d, d] = new_sig 48 | J *= new_sig 49 | if material[p] == 0: # Reset deformation gradient to avoid numerical instability 50 | F[p] = ti.Matrix.identity(float, 2) * ti.sqrt(J) 51 | elif material[p] == 2: 52 | F[p] = U @ sig @ V.transpose() # Reconstruct elastic deformation gradient after plasticity 53 | stress = 2 * mu * (F[p] - U @ V.transpose()) @ F[p].transpose() + ti.Matrix.identity(float, 2) * la * J * (J - 1) 54 | stress = (-dt * p_vol * 4 * inv_dx * inv_dx) * stress 55 | affine = stress + p_mass * C[p] 56 | for i, j in ti.static(ti.ndrange(3, 3)): # Loop over 3x3 grid node neighborhood 57 | offset = ti.Vector([i, j]) 58 | dpos = (offset.cast(float) - fx) * dx 59 | weight = w[i][0] * w[j][1] 60 | grid_v[base + offset] += weight * (p_mass * v[p] + affine @ dpos) 61 | grid_m[base + offset] += weight * p_mass 62 | for i, j in grid_m: 63 | if grid_m[i, j] > 0: # No need for epsilon here 64 | grid_v[i, j] = (1 / grid_m[i, j]) * grid_v[i, j] # Momentum to velocity 65 | 66 | grid_v[i, j][1] -= dt * grid_g[i,j][1] # gravity 67 | 68 | if i < 3 and grid_v[i, j][0] < 0: grid_v[i, j][0] = 0 # Boundary conditions 69 | if i > n_grid - 3 and grid_v[i, j][0] > 0: grid_v[i, j][0] = 0 70 | if j < 3 and grid_v[i, j][1] < 0: grid_v[i, j][1] = 0 71 | if j > n_grid - 3 and grid_v[i, j][1] > 0: grid_v[i, j][1] = 0 72 | for p in x: # grid to particle (G2P) 73 | base = (x[p] * inv_dx - 0.5).cast(int) 74 | fx = x[p] * inv_dx - base.cast(float) 75 | w = [0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1.0) ** 2, 0.5 * (fx - 0.5) ** 2] 76 | new_v = ti.Vector.zero(float, 2) 77 | new_C = ti.Matrix.zero(float, 2, 2) 78 | for i, j in ti.static(ti.ndrange(3, 3)): # loop over 3x3 grid node neighborhood 79 | dpos = ti.Vector([i, j]).cast(float) - fx 80 | g_v = grid_v[base + ti.Vector([i, j])] 81 | weight = w[i][0] * w[j][1] 82 | new_v += weight * g_v 83 | new_C += 4 * inv_dx * weight * g_v.outer_product(dpos) 84 | v[p], C[p] = new_v, new_C 85 | x[p] += dt * v[p] # advection 86 | 87 | @ti.func 88 | def radius(theta): 89 | r = 0.0 90 | t = 3.4 91 | b = 10.0 92 | a = 1/(ti.log(b)*pow(b,t*np.pi)) 93 | th = t * np.pi 94 | r0 = (th - a * (pow(b,th)-1))/50 95 | if theta < th: 96 | r = (theta - a * (pow(b,theta)-1))/50 97 | else: 98 | r = r0 99 | return r 100 | #group_size = n_particles // 3 101 | @ti.kernel 102 | def initialize(): 103 | for i,j in grid_g: 104 | grid_g[i,j] = [0, (n_grid - j)/n_grid * 100] 105 | 106 | center = [0.5,0.5] 107 | r1 = radius(1000) 108 | r0 = r1*1.2 109 | print(r1) 110 | for i in range(n_particles): 111 | #x[i] = [ti.random() * 0.2 + 0.3 + 0.10 * (i // group_size), ti.random() * 0.2 + 0.05 + 0.32 * (i // group_size)] 112 | #material[i] = i // group_size # 0: fluid 1: jelly 2: snow 113 | x[i] = [ti.random() * r0 * 2 + center[0] - r0, ti.random() * r0 *2 + center[1] - r0] 114 | r_i = x[i]-center 115 | r_in = r_i.norm() 116 | theta_i = ti.asin(r_i[1]/r_in) 117 | theta_1 = 0.0 118 | theta_2 = 0.0 119 | 120 | if r_in <= r1: 121 | if theta_i >= 0: 122 | if r_i[0] * r_i[1] >= 0: 123 | theta_1 = theta_i + np.pi 124 | else: 125 | theta_1 = 2*np.pi - theta_i 126 | else: 127 | if r_i[0] * r_i[1] >= 0: 128 | theta_1 = -theta_i 129 | else: 130 | theta_1 = np.pi + theta_i 131 | 132 | if theta_i >= 0: 133 | if r_i[0] * r_i[1] >= 0: 134 | theta_2 = theta_i 135 | else: 136 | theta_2 = np.pi - theta_i 137 | else: 138 | if r_i[0] * r_i[1] >= 0: 139 | theta_2 = np.pi - theta_i 140 | else: 141 | theta_2 = 2*np.pi + theta_i 142 | 143 | r11 = radius(theta_1) 144 | r22 = radius(theta_2) 145 | flag = 0 146 | if r11 > r22: 147 | flag = 1 148 | for j in range(5): 149 | if flag == 0: 150 | rr = radius(theta_1) 151 | if r_in <= rr: 152 | break 153 | else: 154 | flag = 1 155 | theta_1 = theta_1 + 2*np.pi 156 | else: 157 | rr = radius(theta_2) 158 | if r_in <= rr: 159 | break 160 | else: 161 | flag = 0 162 | theta_2 = theta_2 + 2*np.pi 163 | material[i] = flag 164 | 165 | v[i] = ti.Matrix([0, 0]) 166 | F[i] = ti.Matrix([[1, 0], [0, 1]]) 167 | Jp[i] = 1 168 | initialize() 169 | gui = ti.GUI("Taichi MLS-MPM-LOGO", res=512, background_color=0x000000) 170 | while not gui.get_event(ti.GUI.ESCAPE, ti.GUI.EXIT): 171 | for s in range(int(2e-3 // dt)): 172 | substep() 173 | colors = np.array([0xFFFFFF, 0x6495ED], dtype=np.uint32) 174 | gui.circles(x.to_numpy(), radius=1.5, color=colors[material.to_numpy()]) 175 | gui.show() # Change to gui.show(f'{frame:06d}.png') to write images to disk 176 | --------------------------------------------------------------------------------