-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathextendablegrid.jl
More file actions
940 lines (762 loc) · 23.9 KB
/
extendablegrid.jl
File metadata and controls
940 lines (762 loc) · 23.9 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
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
##################################################################
# Abstract types
"""
$(TYPEDEF)
Apex type for grid components.
"""
abstract type AbstractGridComponent <: AbstractExtendableGridApexType end
"""
$(TYPEDEF)
Grid type wrapping Dict
"""
mutable struct ExtendableGrid{Tc, Ti}
components::Dict{Type{<:AbstractGridComponent}, Any}
ExtendableGrid{Tc, Ti}() where {Tc, Ti} = new(Dict{Type{<:AbstractGridComponent}, Any}())
end
"""
````
Base.getindex(grid::ExtendableGrid,T::Type{<:AbstractGridComponent})
````
Generic method for obtaining grid component.
This method is mutating in the sense that non-existing grid components
are created on demand.
Due to the fact that components are stored as Any the return
value triggers type instability. To prevent this, specialized methods must be (and are) defined.
"""
Base.getindex(grid::ExtendableGrid, T::Type{<:AbstractGridComponent}) = get!(grid, T)
"""
````
const ElementInfo{T}=Union{Vector{T},VectorOfConstants{T}}
````
Union type for element information arrays. If all elements have
the same information, it can be stored in an economical form
as a [`VectorOfConstants`](@ref).
"""
const ElementInfo{T} = Union{Vector{T}, VectorOfConstants{T}}
"""
$(TYPEDEF)
1D Array of floating point data
"""
abstract type AbstractGridFloatArray1D <: AbstractGridComponent end
function Base.getindex(grid::ExtendableGrid{Tc, Ti}, T::Type{<:AbstractGridFloatArray1D})::Array{Tc, 1} where {Tc, Ti}
return get!(grid, T)
end
"""
$(TYPEDEF)
2D Array of floating point data
"""
abstract type AbstractGridFloatArray2D <: AbstractGridComponent end
function Base.getindex(grid::ExtendableGrid{Tc, Ti}, T::Type{<:AbstractGridFloatArray2D})::Array{Tc, 2} where {Tc, Ti}
return get!(grid, T)
end
"""
$(TYPEDEF)
1D Array of integer data
"""
abstract type AbstractGridIntegerArray1D <: AbstractGridComponent end
function Base.getindex(grid::ExtendableGrid{Tc, Ti}, T::Type{<:AbstractGridIntegerArray1D})::Array{Ti, 1} where {Tc, Ti}
return get!(grid, T)
end
"""
$(TYPEDEF)
2D Array of integer data
"""
abstract type AbstractGridIntegerArray2D <: AbstractGridComponent end
function Base.getindex(grid::ExtendableGrid{Tc, Ti}, T::Type{<:AbstractGridIntegerArray2D})::Array{Ti, 1} where {Tc, Ti}
return get!(grid, T)
end
"""
$(TYPEDEF)
Integer number
"""
abstract type AbstractGridIntegerConstant <: AbstractGridComponent end
function Base.getindex(grid::ExtendableGrid{Tc, Ti}, T::Type{<:AbstractGridIntegerConstant})::Ti where {Tc, Ti}
return get!(grid, T)
end
"""
$(TYPEDEF)
Floating point number
"""
abstract type AbstractGridFloatConstant <: AbstractGridComponent end
function Base.getindex(grid::ExtendableGrid{Tc, Ti}, T::Type{<:AbstractGridFloatConstant})::Tc where {Tc, Ti}
return get!(grid, T)
end
"""
$(TYPEDEF)
Any kind of adjacency between grid components
"""
abstract type AbstractGridAdjacency <: AbstractGridComponent end
function Base.getindex(grid::ExtendableGrid{Tc, Ti}, T::Type{<:AbstractGridAdjacency})::Adjacency{Ti} where {Tc, Ti}
return get!(grid, T)
end
"""
$(TYPEDEF)
Array of element geometry information.
"""
abstract type AbstractElementGeometries <: AbstractGridComponent end
function Base.getindex(
grid::ExtendableGrid{Tc, Ti},
T::Type{<:AbstractElementGeometries}
)::ElementInfo{ElementGeometries} where {Tc, Ti}
return get!(grid, T)
end
"""
$(TYPEDEF)
Array of element region number information.
"""
abstract type AbstractElementRegions <: AbstractGridComponent end
function Base.getindex(grid::ExtendableGrid{Tc, Ti}, T::Type{<:AbstractElementRegions})::ElementInfo{Ti} where {Tc, Ti}
return get!(grid, T)
end
"""
$(TYPEDEF)
Coordinate system
"""
abstract type CoordinateSystem <: AbstractGridComponent end
function Base.getindex(grid::ExtendableGrid{Tc, Ti}, T::Type{CoordinateSystem})::CoordinateSystems where {Tc, Ti}
return get!(grid, T)
end
##################################################################
# Component key types: for these, access is type stable
"""
$(TYPEDEF)
Node coordinates
"""
abstract type Coordinates <: AbstractGridFloatArray2D end
"""
$(TYPEDEF)
Adjacency describing nodes per grid cell
"""
abstract type CellNodes <: AbstractGridAdjacency end
"""
$(TYPEDEF)
Adjacency describing nodes per grid boundary face
"""
abstract type BFaceNodes <: AbstractGridAdjacency end
"""
$(TYPEDEF)
Description of cell geometries
"""
abstract type CellGeometries <: AbstractElementGeometries end
"""
Description of boundary face geometries
$(TYPEDEF)
"""
abstract type BFaceGeometries <: AbstractElementGeometries end
"""
$(TYPEDEF)
Cell region number per cell
"""
abstract type CellRegions <: AbstractElementRegions end
"""
$(TYPEDEF)
Boundary region number per boundary face
"""
abstract type BFaceRegions <: AbstractElementRegions end
"""
$(TYPEDEF)
Number of cell regions
"""
abstract type NumCellRegions <: AbstractGridIntegerConstant end
"""
$(TYPEDEF)
Number of boundary face regions
"""
abstract type NumBFaceRegions <: AbstractGridIntegerConstant end
"""
$(TYPEDEF)
Boundary edge region number per boundary edge
"""
abstract type BEdgeRegions <: AbstractElementRegions end
"""
$(TYPEDEF)
Number of boundary edge regions
"""
abstract type NumBEdgeRegions <: AbstractGridIntegerConstant end
############################################################
# Generic component methods
"""
$(TYPEDSIGNATURES)
Default veryform method.
"veryform" means "verify and/or transform" and is called to check
and possibly transform components to be added to the grid via `setindex!`.
The default method just passes data through.
"""
veryform(grid::ExtendableGrid, v, ::Type{<:AbstractGridComponent}) = v
"""
$(TYPEDSIGNATURES)
Set new grid component
"""
Base.setindex!(grid::ExtendableGrid, v, T::Type{<:AbstractGridComponent}) = grid.components[T] = veryform(grid, v, T)
"""
$(TYPEDSIGNATURES)
Remove grid component
"""
Base.delete!(grid::ExtendableGrid, T::Type{<:AbstractGridComponent}) = delete!(grid.components, T)
"""
$(TYPEDSIGNATURES)
Reinstantiate grid component (only if it exists)
"""
update!(grid::ExtendableGrid, T::Type{<:AbstractGridComponent}) = haskey(grid, T) ? instantiate(grid, T) : nothing
"""
$(TYPEDSIGNATURES)
To be called by getindex. This triggers lazy creation of
non-existing gridcomponents
"""
Base.get!(grid::ExtendableGrid, T::Type{<:AbstractGridComponent}) = get!(
() -> veryform(grid, instantiate(grid, T), T),
grid.components, T
)
"""
$(TYPEDSIGNATURES)
"Hook" for methods instantiating lazy components.
"""
function instantiate end
############################################################
# Verification of inserted data
"""
````
veryform(grid::ExtendableGrid{Tc,Ti},v,T::Type{<:AbstractGridAdjacency}) where{Tc,Ti}
````
Check proper type of adjacencies upon insertion
"""
veryform(grid::ExtendableGrid{Tc, Ti}, v, T::Type{<:AbstractGridAdjacency}) where {Tc, Ti} = typeof(v) <: Adjacency{Ti} ? v :
throw("Type mismatch")
############################################################
# Instantiation methods
"""
$(TYPEDSIGNATURES)
Instantiate number of cell regions
"""
instantiate(grid, ::Type{NumCellRegions}) = maximum(grid[CellRegions])
"""
$(TYPEDSIGNATURES)
Instantiate number of bface regions
"""
instantiate(grid, ::Type{NumBFaceRegions}) = length(grid[BFaceRegions]) > 0 ? maximum(grid[BFaceRegions]) : 0
"""
$(TYPEDSIGNATURES)
Instantiate number of boundary edge regions
"""
instantiate(grid, ::Type{NumBEdgeRegions}) = maximum(grid[BEdgeRegions])
function prepare_bedgeregions!(grid::ExtendableGrid)
bedges = grid[BEdgeNodes]
bedgeregions = zeros(Int32, num_bedges(grid))
return grid[BEdgeRegions] = bedgeregions
end
instantiate(grid, ::Type{BEdgeRegions}) = prepare_bedgeregions!(grid)
#############################################################
# General methods
"""
$(TYPEDSIGNATURES)
Print the hierarchy of grid component key types (subtypes of [`AbstractGridComponent`](@ref).
This includes additionally user defined subptypes.
"""
gridcomponents() = AbstractTrees.print_tree(AbstractGridComponent)
"""
$(TYPEDSIGNATURES)
Keys in grid
"""
Base.keys(g::ExtendableGrid) = Base.keys(g.components)
"""
$(TYPEDSIGNATURES)
Check if key is in grid
"""
Base.haskey(g::ExtendableGrid, k) = Base.haskey(g.components, k)
"""
$(SIGNATURES)
Space dimension of grid
"""
dim_space(grid::ExtendableGrid) = haskey(grid, Coordinates) ? size(grid[Coordinates], 1) : 0
"""
$(SIGNATURES)
Grid dimension dimension of grid (larges element dimension)
"""
dim_grid(grid::ExtendableGrid) = dim_element(grid[CellGeometries][1])
"""
$(SIGNATURES)
Number of nodes in grid
"""
num_nodes(grid::ExtendableGrid)::Int = haskey(grid, Coordinates) ? size(grid[Coordinates], 2) : 0
"""
$(TYPEDSIGNATURES)
Number of cells in grid
"""
num_cells(grid::ExtendableGrid) = haskey(grid, CellNodes) ? num_sources(grid[CellNodes]) : 0
"""
$(TYPEDSIGNATURES)
Number of boundary faces in grid.
"""
num_bfaces(grid::ExtendableGrid) = haskey(grid, BFaceNodes) ? num_sources(grid[BFaceNodes]) : 0
"""
$(TYPEDSIGNATURES)
Number of boundary edges in grid.
"""
num_bedges(grid::ExtendableGrid) = haskey(grid, BEdgeNodes) ? num_sources(grid[BEdgeNodes]) : 0
"""
$(TYPEDSIGNATURES)
Maximum cell region number
"""
num_cellregions(grid::ExtendableGrid) = grid[NumCellRegions]
"""
$(TYPEDSIGNATURES)
Maximum boundary face region numbers
"""
num_bfaceregions(grid::ExtendableGrid) = grid[NumBFaceRegions]
"""
$(TYPEDSIGNATURES)
Maximum boundary edge region numbers
"""
num_bedgeregions(grid::ExtendableGrid) = grid[NumBEdgeRegions]
"""
$(SIGNATURES)
Type of coordinates in grid
"""
coord_type(grid::ExtendableGrid{Tc, Ti}) where {Tc, Ti} = Tc
"""
$(SIGNATURES)
Type of indices
"""
index_type(grid::ExtendableGrid{Tc, Ti}) where {Tc, Ti} = Ti
function dangling_nodes(grid)
coord = grid[Coordinates]
nnodes = size(coord, 2)
nodemark = zeros(Bool, nnodes)
cn = grid[CellNodes]
ncells = num_cells(grid)
for icell in 1:ncells
for inode in 1:num_targets(cn, icell)
nodemark[cn[inode, icell]] = true
end
end
if all(nodemark)
return nothing
else
return coord[:, findall(!, nodemark)]
end
end
"""
isconsistent(grid; warnonly=false)
Check consistency of grid: a grid is consistent if
- Grid has no dangling nodes
- ... more to be added
If grid is consistent, return true, otherwise throw an error,
or, if `warnoly==true`, return false.
"""
function isconsistent(grid; warnonly = false)
consistent = true
nnodes = num_nodes(grid)
if maximum(grid[CellNodes]) != nnodes
@warn "maximum(grid[CellNodes])!=nnodes"
consistent = false
end
if minimum(grid[CellNodes]) != 1
@warn "minimum(grid[CellNodes])!=1"
consistent = false
end
if length(grid[BFaceNodes]) > 0
if maximum(grid[BFaceNodes]) > nnodes
@warn "maximum(grid[BFaceNodes])>nnodes"
consistent = false
end
if minimum(grid[BFaceNodes]) < 1
@warn "minimum(grid[BFaceNodes])<1"
consistent = false
end
end
dnodes = dangling_nodes(grid)
if !isnothing(dnodes)
@warn "Found dangling nodes: $(dnodes)"
consistent = false
end
if !consistent && ! warnonly
error("Consistency error(s) found in grid")
end
return consistent
end
"""
map(f,grid)
Map function `f` returning a number onto node coordinates of grid.
Returns a vector of length corresponding to the number of nodes of the grid.
The function can take either a vector or a numbers as arguments.
E.g. for a two-dimensional grid `g`, both
```
map(X->X[1]+X[2], g)
```
and
```
map((x,y)->x+y, g)
```
are possible.
"""
function Base.map(f::Function, grid::ExtendableGrid{Tc, Ti}) where {Tc, Ti}
coord = grid[Coordinates]
c1 = coord[:, 1]
dim = dim_space(grid)
## Check if f can be called with number args like f(x,y)
function checknumargs(f, args...)
if !hasmethod(f, Tuple(typeof.(args)))
return false
end
try
y = f(args...)
catch e
if isa(e, MethodError)
return false
end
if isa(e, BoundsError)
return false
end
rethrow(e)
end
return true
end
## Check if f can be called with vector args like f(X::Vector) and returns a number
function checkvecargs(f, v)
if !hasmethod(f, Tuple{Vector})
return false
end
try
y = f(v)
catch e
if isa(e, MethodError)
return false
end
rethrow(e)
end
return true
end
use_numargs = checknumargs(f, c1...)
use_vecargs = checkvecargs(f, c1)
return if use_numargs
if dim == 1
@views Base.map(f, coord[1, :])
elseif dim == 2
@views Base.map(f, coord[1, :], coord[2, :])
else
@views Base.map(f, coord[1, :], coord[2, :], coord[3, :])
end
elseif use_vecargs
Base.map(f, reinterpret(reshape, SVector{dim, Tc}, coord))
else
error("Cannot map function $f on grid. Check for consistency of function args and grid dimension.")
end
end
#
# Define two show methods, one extended for printing the repl, one
# compact for e.g. interpolating into a string
# See https://discourse.julialang.org/t/show-and-showcompact-on-custom-types/8493/6
#
function Base.show(io::IO, ::MIME"text/plain", grid::ExtendableGrid)
str = @sprintf(
"%s\n dim = %7d\n nnodes = %7d\n ncells = %7d\n nbfaces = %7d",
typeof(grid),
dim_space(grid), num_nodes(grid), num_cells(grid), num_bfaces(grid)
)
if num_edges(grid) > 0
str *= @sprintf("\n nedges = %7d", num_edges(grid))
end
if num_partitions(grid) > 1
str *= "\n npartitions/color = $(num_partitions_per_color(grid))"
end
print(io, str)
return nothing
end
function Base.show(io::IO, grid::ExtendableGrid)
str = @sprintf(
"%s(dim=%d, nnodes=%d, ncells=%d, nbfaces=%d",
typeof(grid),
dim_space(grid), num_nodes(grid), num_cells(grid), num_bfaces(grid)
)
if num_edges(grid) > 0
str *= @sprintf(", nedges=%d", num_edges(grid))
end
if num_partitions(grid) > 1
str *= ", npart/color=$(num_partitions_per_color(grid))"
end
str *= ")"
print(io, str)
return nothing
end
### Tests for the gmsh extension:
function multidimsort(A)
i1 = sortperm(A[1, :])
A1 = A[:, i1]
for j in 2:size(A, 1)
cm = countmap(A1[j - 1, :])
for (key, val) in cm
if val > 1 #if there only is one entry with this key, the reordering is not necessary
inds = findall(z -> z == key, A1[j - 1, :]) #indices of that key in A1
sorted_inds = sortperm(A1[j, inds])
A1[:, inds] = A1[:, inds[sorted_inds]] #reorder
end
end
end
return A1
end
"""
seemingly_equal(grid1, grid2; sort=false, confidence=:full
Recursively check seeming equality of two grids. Seemingly means
that long arrays are only compared via random samples.
Keyword args:
- `sort`: if true, sort grid points
- `confidence`: Confidence level:
- :low : Point numbers etc are the same
- :full : all arrays are equal (besides the coordinate array, the arrays only have to be equal up to permutations)
"""
function seemingly_equal(grid1::ExtendableGrid, grid2::ExtendableGrid; sort = false, confidence = :full)
if !sort
for key in keys(grid1)
if !haskey(grid2, key)
return false
end
if !seemingly_equal(grid1[key], grid2[key])
return false
end
end
return true
end
if confidence == :full
for key in keys(grid1)
if !haskey(grid2, key)
return false
end
if !isa(grid1[key], AbstractArray)
!seemingly_equal(grid1[key], grid2[key]) && return false
continue
end
s1 = size(grid1[key])
s2 = size(grid2[key])
if length(s1) == 0
if length(s1) == 1
if eltype(grid1[key]) <: Number
ind1 = sortperm(grid1[key])
ind2 = sortperm(grid2[key])
sa1 = grid1[key][ind1]
sa2 = grid2[key][ind2]
!seemingly_equal(sa1, sa2) && return false
else
!seemingly_equal(grid1[key], grid2[key]) && return false
end
else
if eltype(grid1[key]) <: Number && key != Coordinates
sa1 = multidimsort(sort(grid1[key]; dims = 1))
sa2 = multidimsort(sort(grid2[key]; dims = 1))
!seemingly_equal(sa1, sa2) && return false
else
!seemingly_equal(grid1[key], grid2[key]) && return false
end
end
end
end
return true
elseif confidence == :low
grid1_data = (num_nodes(grid1), num_cells(grid1), num_bfaces(grid1))
grid2_data = (num_nodes(grid2), num_cells(grid2), num_bfaces(grid2))
return grid1_data == grid2_data
else
error("Confidence level $(confidence) not implemented")
return false
end
end
"""
$(SIGNATURES)
Check for seeming equality of two arrays by random sample.
"""
function seemingly_equal(array1::AbstractArray, array2::AbstractArray)
if size(array1) != size(array2)
return false
end
l = length(array1)
ntests = Float64(min(l, 50))
p = min(0.5, ntests / l)
for i in randsubseq(1:l, p)
if !seemingly_equal(array1[i], array2[i])
return false
end
end
return true
end
function seemingly_equal(a1::VariableTargetAdjacency, a2::VariableTargetAdjacency)
return seemingly_equal(a1.colentries, a2.colentries) && seemingly_equal(a1.colstart, a2.colstart)
end
seemingly_equal(x1::Type, x2::Type) = (x1 == x2)
seemingly_equal(x1::Number, x2::Number) = (x1 ≈ x2)
seemingly_equal(x1::Any, x2::Any) = (x1 == x2)
function numbers_match(grid, nn, nc, nb)
return num_nodes(grid) == nn &&
num_cells(grid) == nc &&
num_bfaces(grid) == nb
end
Base.extrema(grid::ExtendableGrid) = Base.extrema(grid[Coordinates]; dims = 2)
function bbox(grid)
e = extrema(grid)
return map(a -> a[1], e), map(a -> a[2], e)
end
"""
$(SIGNATURES)
Remove precomputed grid components for lightweight storage of the grid.
Use the `keep` list to exclude grid components from trimming.
"""
function trim!(grid::ExtendableGrid; keep = [])
components_for_trimming = [
BEdgeAssemblyGroups,
BEdgeEdges,
BEdgeGeometries,
BEdgeNodes,
BEdgeRegions,
BEdgeVolumes,
BFaceAssemblyGroups,
BFaceCellPos,
BFaceCells,
BFaceEdges,
BFaceFaces,
BFaceNormals,
BFaceVolumes,
CellAssemblyGroups,
CellEdges,
CellEdgeSigns,
CellFaceOrientations,
CellFaces,
CellFaceSigns,
CellVolumes,
EdgeAssemblyGroups,
EdgeCells,
EdgeGeometries,
EdgeNodes,
EdgeRegions,
EdgeTangents,
EdgeVolumes,
FaceAssemblyGroups,
FaceCells,
FaceEdges,
FaceEdgeSigns,
FaceGeometries,
FaceNodes,
FaceNormals,
FaceRegions,
FaceVolumes,
NodeCells,
NodeEdges,
NodeFaces,
NodePatchGroups,
NumBEdgeRegions,
NumBFaceRegions,
NumCellRegions,
UniqueBEdgeGeometries,
UniqueBFaceGeometries,
UniqueCellGeometries,
UniqueEdgeGeometries,
UniqueFaceGeometries,
]
# filter out kept components
filter!(!in(keep), components_for_trimming)
for component in components_for_trimming
delete!(grid, component)
end
return nothing
end
"""
$(SIGNATURES)
Variant of [`trim!`](@ref) without modification of the original grid.
Returns a trimmed copy of the grid.
"""
function trim(grid::ExtendableGrid; keep = [])
grid_copy = deepcopy(grid)
trim!(grid_copy; keep)
return grid_copy
end
"""
$(TYPEDSIGNATURES)
Remove all adjacency information from a grid, creating independent cells by duplicating coordinates
and assigning new node indices while keeping the original coordinates.
This function creates a new grid where each cell has its own independent set of nodes by duplicating
the coordinate information and creating new node indices. The original coordinates are preserved,
but adjacency information is removed.
# Arguments
- `grid::ExtendableGrid`: The input grid to be processed
# Returns
- `::ExtendableGrid`: A new grid with duplicated coordinates and independent cells
"""
function explode(grid::ExtendableGrid)
# create a new grid with the same type parameters
Tc = coord_type(grid)
Ti = index_type(grid)
new_grid = ExtendableGrid{Tc, Ti}()
# get original coordinates and cell-node adjacency
coords = grid[Coordinates]
cellnodes = grid[CellNodes]
# create new coordinates array by duplicating nodes for each cell
n_cells = num_cells(grid)
nodes_per_cell = size(cellnodes, 1)
new_coords = similar(coords, size(coords, 1), n_cells * nodes_per_cell)
# create new cell-node adjacency where each cell gets its own nodes
new_cellnodes = similar(cellnodes)
# fill new coordinates and cell-node adjacency
for icell in 1:n_cells
for inode in 1:nodes_per_cell
original_node = cellnodes[inode, icell]
new_node = (icell - 1) * nodes_per_cell + inode
new_coords[:, new_node] = coords[:, original_node]
new_cellnodes[inode, icell] = new_node
end
end
# assign the new coordinates and cell-node adjacency
new_grid[Coordinates] = new_coords
new_grid[CellNodes] = new_cellnodes
# reference original grid as parent
new_grid[ParentGrid] = grid
new_grid[CellParents] = collect(Ti, 1:n_cells)
# copy other components
if haskey(grid, CellGeometries)
new_grid[CellGeometries] = grid[CellGeometries]
end
if haskey(grid, CellRegions)
new_grid[CellRegions] = grid[CellRegions]
end
# handle boundary face nodes and regions
if haskey(grid, BFaceNodes)
# create new boundary face nodes by duplicating for each cell
bfacenodes = grid[BFaceNodes]
bfacecells = grid[BFaceCells]
n_bfaces = num_bfaces(grid)
nodes_per_bface = size(bfacenodes, 1)
new_bfacenodes = similar(bfacenodes)
# map boundary face nodes to new node indices using cell information
for ibface in 1:n_bfaces
# get the cell this boundary face belongs to
cell_id = bfacecells[1, ibface] # first entry is the cell ID
for inode in 1:nodes_per_bface
original_node = bfacenodes[inode, ibface]
# find the local node index within the cell
local_node_id = -1
for icell_node in 1:nodes_per_cell
if cellnodes[icell_node, cell_id] == original_node
local_node_id = icell_node
break
end
end
if local_node_id > 0
# calculate new node index based on cell and local node position
new_node = (cell_id - 1) * nodes_per_cell + local_node_id
new_bfacenodes[inode, ibface] = new_node
else
error("Could not find node $original_node in cell $cell_id")
end
end
end
new_grid[BFaceNodes] = new_bfacenodes
end
# transfer other components
for Component in [
BFaceRegions,
CellGeometries,
BFaceGeometries,
CoordinateSystem,
]
if haskey(grid, Component)
new_grid[Component] = grid[Component]
end
end
return new_grid
end