Peano
Loading...
Searching...
No Matches
ExtractFineGrid.py
Go to the documentation of this file.
1# This file is part of the Peano project. For conditions of distribution and
2# use, please see the copyright notice at www.peano-framework.org
3from .Filter import Filter
4
5
7 """
8 Extract the fine grid information
9
10 This is a very expensive filter if it is applied on large patch
11 sets, as it has to compare each patch with each other patch.
12 If you want to use it in an economically sensible way, I
13 recommend that you first apply other, cheaper filters to bring
14 the patch count down.
15
16 Even though the overlap operation is idempotent - if a patch
17 is not a fine grid patch within a small local dataset written
18 by one tree, then it can't be part of the fine grid in the
19 overall data set - I found that it is usually faster to
20 concatenate all data and then to apply the filter.
21 """
22
23 def __init__(self, run_on_individual_pieces_of_data=False, verbose=False):
24 Filter.__init__(self, run_on_individual_pieces_of_data, True, verbose)
25 pass
26
27 def __patches_overlap(self, a, b, dimensions):
28 """
29 When we extract the fine grid patches, we rely on a
30 patch overlap. With floating point precision which is
31 often smaller then IEEE single (for a lot of vis tools
32 or formats, respectively), I try to be rather careful
33 with throwing away patches - otherwise, you quickly end
34 up with vis where small pieces are missing.
35
36 I therefore introduce an expansion factor. I throw away
37 patches if they overlap. So to be more pessimistic, the
38 expansion has to be set negative.
39
40 a: tarch.plotter.api.Patch
41
42 b: tarch.plotter.api.Patch
43 """
44 result = False
45
46 if dimensions == 3:
47 Expansion = -0.1 * min(
48 a.size[0], b.size[0], a.size[1], b.size[1], a.size[2], b.size[2]
49 )
50 result = (
51 a.offset[0] + a.size[0] + Expansion > b.offset[0]
52 and a.offset[1] + a.size[1] + Expansion > b.offset[1]
53 and a.offset[2] + a.size[2] + Expansion > b.offset[2]
54 and a.offset[0] < b.offset[0] + b.size[0] + Expansion
55 and a.offset[1] < b.offset[1] + b.size[1] + Expansion
56 and a.offset[2] < b.offset[2] + b.size[2] + Expansion
57 )
58 else:
59 Expansion = -0.1 * min(a.size[0], b.size[0], a.size[1], b.size[1])
60 result = (
61 a.offset[0] + a.size[0] + Expansion > b.offset[0]
62 and a.offset[1] + a.size[1] + Expansion > b.offset[1]
63 and a.offset[0] < b.offset[0] + b.size[0] + Expansion
64 and a.offset[1] < b.offset[1] + b.size[1] + Expansion
65 )
66
67 return result
68
69 def render(
70 self,
71 cell_data,
72 dof,
73 dimensions,
74 unknowns,
75 is_data_associated_to_cell,
76 description,
77 mapping,
78 ):
79 """
80 Overwrite this one for the particular filter.
81
82 We create an empty result array. Then we run over the input sequence
83 of cell_data. Per element, we check if a cell_data to the right within
84 this input sequence overlaps.
85
86 List operations are very expensive in Python. I therefore implement a
87 two-pass strategy, where I first sort the patches according to their
88 size. Actually, I sort them according to their inverted size, i.e.
89 big entries come first.
90 """
91
92 def sort_key(patch):
93 return patch.size[0]
94
95 if self.verbose:
96 print(
97 "Sort input data to optimise algorithmic efficiency. Small patches come first"
98 )
99 cell_data.sort(reverse=False, key=sort_key)
100
101 # Create array of same length as cell_data, fill it with None
102 new_cell_data = [None for _ in range(len(cell_data))]
103
104 if self.verbose:
105 print(
106 "Build up auxiliary data structures over "
107 + str(len(cell_data))
108 + " entries"
109 )
110
111 new_cell_data[0] = cell_data[0]
112 current_index_in_cell_data = 1
113 current_index_in_new_cell_data = 0
114
115 # I memorise the min h and add a shortcut for the finest cell. This turned out
116 # to be absolutely essential for almost all data
117 min_size = cell_data[current_index_in_cell_data].size[0]
118
119 ratio_of_last_progress_print = 10
120
121 while current_index_in_cell_data < len(cell_data):
122 assert (
123 cell_data[current_index_in_cell_data - 1].size[0]
124 <= cell_data[current_index_in_cell_data].size[0]
125 )
126
127 if cell_data[current_index_in_cell_data].size[0] == min_size:
128 current_index_in_new_cell_data += 1
129 new_cell_data[current_index_in_new_cell_data] = cell_data[
130 current_index_in_cell_data
131 ]
132 current_index_in_cell_data += 1
133 else:
134 overlaps = False
135 check_index = 0
136 while not overlaps and check_index < current_index_in_new_cell_data:
137 overlaps = overlaps or self.__patches_overlap(
138 new_cell_data[check_index],
139 cell_data[current_index_in_cell_data],
140 dimensions,
141 )
142 check_index += 1
143 if overlaps:
144 current_index_in_cell_data += 1
145 else:
146 current_index_in_new_cell_data += 1
147 new_cell_data[current_index_in_new_cell_data] = cell_data[
148 current_index_in_cell_data
149 ]
150 current_index_in_cell_data += 1
151
152 if current_index_in_cell_data > ratio_of_last_progress_print / 100 * len(
153 cell_data
154 ):
155 if self.verbose:
156 print("... {}%".format(ratio_of_last_progress_print))
157 ratio_of_last_progress_print += 10
158
159 current_index_in_new_cell_data += 1
160 if self.verbose:
161 print(
162 "Extracted "
163 + str(current_index_in_new_cell_data)
164 + " from the "
165 + str(len(cell_data))
166 + " patch(es)"
167 )
168 new_cell_data = new_cell_data[0:current_index_in_new_cell_data]
169
170 return (
171 new_cell_data,
172 dof,
173 dimensions,
174 unknowns,
175 is_data_associated_to_cell,
176 description,
177 mapping,
178 )
__init__(self, run_on_individual_pieces_of_data=False, verbose=False)
exploit_idempotent: boolean Exploit the fact that the filter is idempotent, i.e.
__patches_overlap(self, a, b, dimensions)
When we extract the fine grid patches, we rely on a patch overlap.
An abstract filter class.
Definition Filter.py:5