-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathlagrangePoly_isosurfacePlot_driver.jl
More file actions
282 lines (235 loc) · 9.38 KB
/
lagrangePoly_isosurfacePlot_driver.jl
File metadata and controls
282 lines (235 loc) · 9.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
#specify packages to be used for code
using SimplexGridFactory, ExtendableGrids
using LinearAlgebra
using TetGen
using BenchmarkTools
using Polyester
using GridVisualize, GLMakie
using GeometryBasics
using Colors
#create geometry for domain of interest
function tetrahedralization_of_cube(; xlims=(-1,1), ylims=(-1,1), zlims=(-1,1), maxvolume=.01)
#set default parameters for a unit cube w/ max element volume size of 0.01
#these values can be varied when calling the function
#use TetGen to build geometry
builder=SimplexGridBuilder(Generator=TetGen)
#create pts
p1=point!(builder, xlims[1], ylims[1], zlims[1])
p2=point!(builder, xlims[2], ylims[1], zlims[1])
p3=point!(builder, xlims[2], ylims[2], zlims[1])
p4=point!(builder, xlims[1], ylims[2], zlims[1])
p5=point!(builder, xlims[1], ylims[1], zlims[2])
p6=point!(builder, xlims[2], ylims[1], zlims[2])
p7=point!(builder, xlims[2], ylims[2], zlims[2])
p8=point!(builder, xlims[1], ylims[2], zlims[2])
#create faces
facetregion!(builder,1)
facet!(builder, p1 ,p2, p3 ,p4)
facetregion!(builder,2)
facet!(builder, p5 ,p6, p7 ,p8)
facetregion!(builder,3)
facet!(builder, p1, p2, p6 ,p5)
facetregion!(builder,4)
facet!(builder, p2, p3 ,p7 ,p6)
facetregion!(builder,5)
facet!(builder, p3, p4 ,p8 ,p7)
facetregion!(builder,6)
facet!(builder, p4, p1 ,p5 ,p8)
#mesh over domain
meshy = simplexgrid(builder,maxvolume=maxvolume)
#return mesh for whole domain
return meshy
end
#calculate function values at each of the chebyshev node points
function ufunc(xx,yy,zz)
#pre-allocate matrix to hold chebyshev node point function evaluations
uGrid = zeros(length(xx),length(yy),length(zz))
#for our specific test function, we need to find the midpt of our conecentric spheres
mid = mean(xx)
#find function values at each of the chebyshev pts
#plot concentric spheres a test function for the domain section of interest
for i = 1:length(xx)
for j = 1:length(yy)
for k = 1:length(zz)
uGridx = xx[i]-mid
uGridy = yy[j]-mid
uGridz = zz[k]-mid
uGrid[i,j,k] = sqrt(uGridx^2+uGridy^2+uGridz^2)
end
end
end
#return matrix holding function evaluations of all chebyshev pts on a grid
return uGrid
end
#find wj weight values in x-, y-, z-directions for barycentric lagrange polynomial implementation
#reference paper: https://people.maths.ox.ac.uk/trefethen/barycentric.pdf
function bary(xx,yy,zz)
#pre-allocate vectors to hold weights in x-, y-, z-directions
wx = zeros(1,length(xx))
wy = zeros(1,length(yy))
wz = zeros(1,length(zz))
#calculate weights wj in x-direction
for j = 1:length(xx)
wjx = 1
for k = 1:length(xx)
#exclude the case where we divide by zero
if !(xx[j] ≈ xx[k])
wjx = wjx * 1 / (xx[j]-xx[k])
end
end
wx[j] = wjx
end
#calculate weights wj in y-direction
for j = 1:length(yy)
wjy = 1
for k = 1:length(yy)
#exclude the case where we divide by zero
if !(yy[j] ≈ yy[k])
wjy = wjy * 1 / (yy[j]-yy[k])
end
end
wy[j] = wjy
end
#calculate weights wj in z-direction
for j = 1:length(zz)
wjz = 1
for k = 1:length(zz)
#exclude the case where we divide by zero
if !(zz[j] ≈ zz[k])
wjz = wjz * 1 / (zz[j] - zz[k])
end
end
wz[j] = wjz
end
#return vectors holding wj wight values in x-, y-, z-directions
return wx, wy, wz
end
#calculate function values at the nodal pts found in the original TetGen 3D mesh generation
function unitPlot(xVec,yVec,zVec,xx,yy,zz,uGrid)
#find the wj weight values in the x-, y-, z-directions
wx, wy, wz = bary(xx, yy, zz)
#pre-allocate a vector to hold function values at each of the TetGen nodal pts
plotty = zeros(length(xVec))
#find function values for TetGen nodal pts
@batch for g = 1:length(xVec)
#specify the x,y,z coordinates of the TetGen nodal pts for this loop
x=xVec[g]
y=yVec[g]
z=zVec[g]
#set various sum variables to zero for each loop
#this ensures the summations in equation 4.2 from
#https://people.maths.ox.ac.uk/trefethen/barycentric.pdf
#can be calculated
sum = 0
sumid = 0
sumjd = 0
sumkd = 0
#sum over wj weights in the z-direction while dividing by z-grid pts
#this becomes part of the denominator of eqn 4.2
for k =1:length(zz)
#avoid dividing by zero
if !(z ≈ zz[k])
sumkd = sumkd + wz[k] / (z - zz[k])
end
end
#sum over wj weights in the y-direction while dividing by y-grid pts
#this becomes part of the denominator of eqn 4.2
for j =1:length(yy)
#avoid dividing by zero
if !(y ≈ yy[j])
sumjd = sumjd + wy[j] / (y - yy[j])
end
end
#sum over wj weights in the x-direction while dividing by x-grid pts
#this becomes part of the denominator of eqn 4.2
for i =1:length(xx)
#avoid dividing by zero
if !(x ≈ xx[i])
sumid = sumid + wx[i] / (x - xx[i])
end
end
#put numerator and denominator of eqn 4.2 together
#multiply summations together as needed
for i = 1:length(xx)
for j = 1:length(yy)
for k =1:length(zz)
#avoid dividing by zero
if !(z ≈ zz[k]) && !(y ≈ yy[j]) && !(x ≈ xx[i])
sum = sum + uGrid[i,j,k] * (wz[k]/(z - zz[k]))/sumkd * (wy[j]/(y - yy[j]))/sumjd * (wx[i]/(x - xx[i]))/sumid
end
end
end
end
#store the approximation for each TetGen nodal point in the plotty vector
plotty[g] = sum
end
#return a vector containing function values for the TetGen nodal pts
return plotty
end
#set limits for each of the unit cubes
xyzlims = ([-3*pi,-pi], [-pi,pi], [pi,3*pi])
#specify isosurfaces of interest for each unit block
fmat = [1 1.15 1.25 1.5; 1 1.15 1.25 1.5; 1 1.15 1.25 1.5]
list_of_flevels = [fmat[i,:] for i in 1:size(fmat,1)]
#no planar surfaces are of interest, other than the isosurfaces specified
#this is important to note, as a non-empty planes vector will alter the
#output of the marching_tetrahedra algorithm
planes = []
#create empty vectors to hold isosurface mesh data and the colors corresponding to each mesh
list_of_meshes=[]
list_of_colors=[]
#find isosurfaces for each unit cube of interest
for j = 1:3
#mesh over 3D domain
meshy = tetrahedralization_of_cube(xlims=xyzlims[j], ylims=xyzlims[j], zlims=xyzlims[j], maxvolume=0.25)
#extract coordinates and connectivity matrix from mesh
coord = meshy.components[Coordinates]
cellnodes = meshy.components[CellNodes] #connectivity matrix
#find point-wise coordinates on mesh split into x-, y-, z-components
xVec,yVec,zVec = (meshy.components[Coordinates][i,:] for i = 1:3)
#create chebyshev nodes
n = 7
θ = LinRange(0, pi, n+1)
xn = sort(cos.(θ))
#set chebyshev nodes over interval of interest
xdiff = 0.5 * (xyzlims[j][2] - xyzlims[j][1])
xx = yy = zz = @. xn * xdiff + (xdiff + xyzlims[j][1])
#calculate function values at chebyshev node points
uGrid = ufunc(xx,yy,zz)
#find function values at node points from original TetGen mesh
#note that this is done using the chebyshev node grid and the function
#values at these nodes
func = unitPlot(xVec,yVec,zVec,xx,yy,zz,uGrid)
#find each isosurface for a given unit block
for i=1:length(list_of_flevels)
#set isosurface value of interest
level = list_of_flevels[i]
#extract details about location isosurface pts using marching tetrahedra algorithm
tet_deets = GridVisualize.marching_tetrahedra(meshy,func,planes,level)
pts, trngls, fvals = tet_deets
#output mesh that encompasses isosurface
makie_triangles = Makie.to_triangles(hcat(getindex.(trngls,1), getindex.(trngls,2), getindex.(trngls,3)))
makie_pts = Makie.to_vertices(pts)
iso_mesh = GeometryBasics.normal_mesh(makie_pts, makie_triangles)
#add newly found mesh to list of meshes
push!(list_of_meshes, iso_mesh)
#add a color to correspond w/ mesh of interest
push!(list_of_colors, RGBA(0.1f0, 0.0f0, 0.0f0, 0.1f0))
end
end
#plot isosurface meshes for each unit cube
fig, ax, plt = Makie.mesh(list_of_meshes[1],color = list_of_colors[1])
for i = 2:length(list_of_meshes)
Makie.mesh!(list_of_meshes[i],color = list_of_colors[i])
end
#display final figure
fig
#store data in struct
#create struct
struct outputInfo
mesh_list
iso_list
domain_lims
end
#specify data inputs to struct
isoGraphInfo = outputInfo(list_of_meshes,list_of_flevels,xyzlims)