Skip to content

Commit 53c253c

Browse files
authored
Merge pull request #29 from ZenanH/main
🎉 Release new version v0.1.22
2 parents 28b4f14 + 1e07420 commit 53c253c

13 files changed

Lines changed: 15611 additions & 40 deletions

File tree

Project.toml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,29 @@
11
name = "MaterialPointGenerator"
22
uuid = "18deba1c-5063-41ee-a388-01f264c5a914"
33
authors = ["ZenanH <zenan.huo@outlook.com>"]
4-
version = "0.1.21"
4+
version = "0.1.22"
55

66
[deps]
77
CondaPkg = "992eb4ea-22a4-4c89-a5bb-47a3300528ab"
88
DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab"
99
Gmsh = "705231aa-382f-11e9-3f0c-b7cb4346fdeb"
10+
GMT = "5752ebe1-31b9-557e-87aa-f909b540aa54"
11+
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
12+
LiveServer = "16fef848-5104-11e9-1b77-fb7a48bbb589"
1013
NearestNeighbors = "b8a86587-4115-5ab1-83bc-aa920d37bbce"
14+
PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
1115
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
1216
PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
17+
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
1318

1419
[compat]
1520
CondaPkg = "0.2"
1621
DelimitedFiles = "1"
1722
Gmsh = "0.3"
23+
GMT = "1.28"
24+
LiveServer = "1.5"
1825
NearestNeighbors = "0.4"
26+
PrecompileTools = "1.2"
1927
PythonCall = "0.9"
2028
julia = "1.11"
2129

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![CI](https://github.com/LandslideSIM/MaterialPointGenerator.jl/actions/workflows/ci.yml/badge.svg)](https://github.com/LandslideSIM/MaterialPointGenerator.jl/actions/workflows/ci.yml)
44
[![Stable](https://img.shields.io/badge/docs-stable-blue.svg?logo=quicklook)](https://LandslideSIM.github.io/MaterialPointGenerator.jl/stable)
55
[![Dev](https://img.shields.io/badge/docs-dev-red.svg?logo=quicklook)](https://LandslideSIM.github.io/MaterialPointGenerator.jl/dev)
6-
[![Version](https://img.shields.io/badge/version-v0.1.21-pink)]()
6+
[![Version](https://img.shields.io/badge/version-v0.1.22-pink)]()
77

88
During the EGU2023 conference, when I presented a high-performance MPM (Material Point Method) solver, I was asked,
99
"How do you discretize the computational model for the MPM?" I didn't have a clear answer (I didn't even consider it a problem) because the models were relatively simple and could be generated directly using some straightforward functions. However, as computational models gradually became more complex and diverse, I began to realize that this was indeed a very good question. The preprocessing for MPM should not be a computationally intensive task; it should be fast enough. Yet, I couldn't find a "plug-and-play" generalized code for this purpose. Some literatures have contributed to this issue, and I built upon their work to create a comprehensive and refined julia package.
@@ -30,6 +30,7 @@ julia> ]
3030
- [x] Particle generation from a Digital Elevation Model (DEM) file
3131
- [x] Automatically interpolate DEM files with support for shape trimming
3232
- [x] Attach attributions to the particles
33+
- [x] SLBL and boundary selector interface
3334

3435
## Showcases 🎲
3536

@@ -45,6 +46,10 @@ julia> ]
4546
|:--------:|:---:|
4647
| <img src="docs/src/example/image9.png" width="300"> | <img src="docs/src/example/image10.png" width="360"> |
4748

49+
| SLBL |
50+
|:----:|
51+
| <img src="docs/src/assets/showcase/slbl_gui.png" width="660"> |
52+
4853
## Acknowledgement 👍
4954

5055
This project is sponserd by [Risk Group | Université de Lausanne](https://wp.unil.ch/risk/) and [China Scholarship Council [中国国家留学基金管理委员会]](https://www.csc.edu.cn/).
944 KB
Loading

src/MaterialPointGenerator.jl

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,25 @@
1111

1212
module MaterialPointGenerator
1313

14-
using DelimitedFiles, CondaPkg, Gmsh, NearestNeighbors, Printf, PythonCall
14+
using CondaPkg, DelimitedFiles, Gmsh, NearestNeighbors, Printf, PythonCall
15+
using LinearAlgebra: mul!, eigen, Symmetric, normalize
16+
using Statistics: mean
17+
using GMT: concavehull
18+
using LiveServer: serve
19+
using PrecompileTools: @setup_workload, @compile_workload
20+
21+
import LinearAlgebra.LAPACK: syev!
1522

1623
const trimesh = PythonCall.pynew()
1724
const np = PythonCall.pynew()
25+
const o3d = PythonCall.pynew()
1826
const MultiPolygon = PythonCall.pynew()
1927
const Polygon = PythonCall.pynew()
28+
const LineString = PythonCall.pynew()
2029
const Point = PythonCall.pynew()
2130
const mapping = PythonCall.pynew()
2231
const unary_union = PythonCall.pynew()
32+
const rotate = PythonCall.pynew()
2333
const rasterio = PythonCall.pynew()
2434
const rasterize = PythonCall.pynew()
2535
const pygmsh = PythonCall.pynew()
@@ -39,9 +49,11 @@ function __init__()
3949
PythonCall.pycopy!(pytime , pyimport("time" ))
4050
# import their submudules
4151
PythonCall.pycopy!(Polygon , pyimport("shapely.geometry" ).Polygon )
52+
PythonCall.pycopy!(LineString , pyimport("shapely.geometry" ).LineString )
4253
PythonCall.pycopy!(Point , pyimport("shapely.geometry" ).Point )
4354
PythonCall.pycopy!(mapping , pyimport("shapely.geometry" ).mapping )
4455
PythonCall.pycopy!(unary_union , pyimport("shapely.ops" ).unary_union )
56+
PythonCall.pycopy!(rotate , pyimport("shapely.affinity" ).rotate )
4557
PythonCall.pycopy!(rasterize , pyimport("rasterio.features" ).rasterize )
4658
PythonCall.pycopy!(pyKDTree , pyimport("scipy.spatial" ).cKDTree )
4759
PythonCall.pycopy!(MultiPolygon, pyimport("shapely.geometry" ).MultiPolygon)
@@ -73,6 +85,16 @@ include(joinpath(@__DIR__, "meshgenerator.jl"))
7385
include(joinpath(@__DIR__, "polygon.jl" ))
7486
include(joinpath(@__DIR__, "polyhedron.jl" ))
7587
include(joinpath(@__DIR__, "dem.jl" ))
88+
include(joinpath(@__DIR__, "slbl/slbl.jl" ))
89+
include(joinpath(@__DIR__, "slbl/slbl_gui.jl"))
7690
include(joinpath(@__DIR__, "utils.jl" ))
7791

92+
@setup_workload begin
93+
points = rand(20, 3)
94+
@compile_workload begin
95+
# functions in utils.jl
96+
getnormals(points)
97+
end
98+
end
99+
78100
end

src/dem.jl

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ Array of the particles, `tree` is the KDTree of the DEM.
3131
@views function IDW!(
3232
k ::T1,
3333
p ::T1,
34-
dem ::Matrix{T2},
35-
idxs ::Matrix{T1},
36-
ptslist::Matrix{T2},
34+
dem ::AbstractMatrix{T2},
35+
idxs ::AbstractMatrix{T1},
36+
ptslist::AbstractMatrix{T2},
3737
tree ::KDTree
3838
) where {T1, T2}
3939
@inbounds Threads.@threads for i in axes(ptslist, 1)
@@ -75,12 +75,12 @@ neighbors (10 by default), `p` is the power parameter (2 by default), `trimbound
7575
boundary of the particles, `dembounds` is the boundary of the DEM.
7676
"""
7777
@views function rasterizeDEM(
78-
dem ::Matrix{T2},
78+
dem ::AbstractMatrix{T2},
7979
h ::T2;
8080
k ::T1 = 10,
8181
p ::T1 = 2,
82-
trimbounds::Matrix{T2}= [0.0 0.0],
83-
dembounds ::Vector{T2}= [0.0, 0.0]
82+
trimbounds::AbstractMatrix{T2}= [0.0 0.0],
83+
dembounds ::AbstractVector{T2}= [0.0, 0.0]
8484
) where {T1, T2}
8585
# check input arguments
8686
size(dem, 2) 3 && throw(ArgumentError("DEM should have three columns: x, y, z"))
@@ -122,16 +122,17 @@ boundary of the particles, `dembounds` is the boundary of the DEM.
122122
# move the models to the grid (space = h)
123123
@. ptslist[:, 3] = ceil(ptslist[:, 3] / h) * h
124124

125-
return ptslist
125+
return sort_pts_xy(ptslist)
126126
end
127127

128128
@views function rasterizeDEM(
129-
dem ::Matrix{T2},
129+
dem ::AbstractMatrix{T2},
130130
h ::T2,
131-
polygon::Py;
132-
k ::T1 = 10,
133-
p ::T1 = 2
134-
) where {T1, T2}
131+
polygon::AbstractMatrix{T2};
132+
k ::Int = 10,
133+
p ::Int = 2
134+
) where T2
135+
pypolygon = Polygon(np.array(polygon))
135136
# check input arguments
136137
size(dem, 2) 3 && throw(ArgumentError("DEM should have three columns: x, y, z"))
137138
h > 0 || throw(ArgumentError("h must be positive"))
@@ -144,12 +145,12 @@ end
144145
ξ0 = meshbuilder(dem_xmin : h : dem_xmax, dem_ymin : h : dem_ymax)
145146
x_test = np.array(ξ0[:, 1])
146147
y_test = np.array(ξ0[:, 2])
147-
v_in_id = pyconvert(Vector, v_contains(polygon, x_test, y_test))
148+
v_in_id = pyconvert(Vector, v_contains(pypolygon, x_test, y_test))
148149
ptslist = hcat(ξ0[v_in_id, :], zeros(T2, count(v_in_id)))
149150

150151
# create KDTree for DEM
151152
tree = KDTree(dem[:, 1:2]')
152-
idxs = zeros(T1, size(ptslist, 1), k)
153+
idxs = zeros(Int, size(ptslist, 1), k)
153154
IDW!(k, p, dem, idxs, ptslist, tree)
154155

155156
# move the models to the grid (space = h)
@@ -158,19 +159,17 @@ end
158159
return ptslist
159160
end
160161

161-
function getpolygon(pts::Matrix)
162-
points = size(pts, 2) == 3 ? np.array(pts[:, 1:2]) : np.array(pts)
163-
164-
@pyexec """
165-
def get_polygon(points, ConvexHull, Polygon):
166-
hull = ConvexHull(points)
167-
hull_points = points[hull.vertices]
168-
polygon = Polygon(hull_points)
169-
return polygon
170-
""" => get_polygon
171-
172-
polygon = get_polygon(points, ConvexHull, Polygon)
173-
return polygon
162+
function getpolygon(pts::AbstractMatrix; ratio=0.1)
163+
pts_col = size(pts, 2)
164+
if pts_col == 2
165+
points = pts
166+
elseif pts_col == 3
167+
points = pts[:, 1:2]
168+
else
169+
throw(ArgumentError("points must be a Nx2 or Nx3 array"))
170+
end
171+
point_polygon = concavehull(points, ratio, false)
172+
return point_polygon.data
174173
end
175174

176175
"""
@@ -183,7 +182,7 @@ Generate particles from a given DEM file. `dem` is a coordinates Array with thre
183182
size in the MPM simulation. `bottom` is a value, which means the plane `z = bottom`.
184183
"""
185184
@views function dem2particle(
186-
dem ::Matrix{T2},
185+
dem ::AbstractMatrix{T2},
187186
h ::T2,
188187
bottom::T2
189188
) where T2
@@ -236,10 +235,10 @@ than the dem. `h` is the space of grid size in `z` direction used in the MPM sim
236235
surfaces. Note that layers are sorted from top to bottom.
237236
"""
238237
@views function dem2particle(
239-
dem ::Matrix{T2},
238+
dem ::AbstractMatrix{T2},
240239
h ::T2,
241240
bottom::T2,
242-
layer ::Vector{Matrix{T2}}
241+
layer ::AbstractVector{AbstractMatrix{T2}}
243242
) where T2
244243
# values check
245244
T1 = T2 == Float32 ? Int32 : Int64
@@ -341,9 +340,9 @@ Array with three columns (x, y, z), which has to be initialized with the struct
341340
than the dem. `h` is the space of grid size in `z` direction used in the MPM simulation.
342341
"""
343342
@views function dem2particle(
344-
dem ::Matrix{T2},
343+
dem ::AbstractMatrix{T2},
345344
h ::T2,
346-
bottom::Matrix{T2}
345+
bottom::AbstractMatrix{T2}
347346
) where T2
348347
# values check
349348
T1 = T2 == Float32 ? Int32 : Int64
@@ -401,9 +400,9 @@ Matrix with three columns (x, y, z), which represents the layer surfaces. Note t
401400
are sorted from top to bottom.
402401
"""
403402
@views function dem2particle(
404-
dem ::Matrix{T2},
403+
dem ::AbstractMatrix{T2},
405404
h ::T2,
406-
bottom::Matrix{T2},
405+
bottom::AbstractMatrix{T2},
407406
layer ::Vector{Matrix{T2}}
408407
) where T2
409408
# values check

0 commit comments

Comments
 (0)