Peano
Loading...
Searching...
No Matches
postProcess.py
Go to the documentation of this file.
1import numpy as np
2
3def parse_patch_file(file_path, solver_type):
4 """
5 Transform data from Peano patch file into numpy array
6 in the format [x_vertex, y_vertex, value]
7
8 :arg file_path: path to Peano patch file
9 :solver_type: "CG" or "DG"
10 """
11
12 if solver_type not in ["CG", "DG"]: raise ValueError("Invalid solver type. Expected 'CG' or 'DG'.")
13
14 with open(file_path, 'r') as file:
15 lines = file.readlines()
16
17 if solver_type == 'CG':
18 # For CG, convert the patch file format into a list:
19 data = [] # the output format is [x, y, val], where (x,y) is vertex coordinates
20 i = 0
21 while i < len(lines):
22 if lines[i].startswith("begin patch"):
23 # Read 'offset x_left_bottom_node_coordinate y_left_bottom_node_coordinate'
24 _, xlb, ylb = lines[i+1].split()
25 xlb = float(xlb)
26 ylb = float(ylb)
27
28 # Read 'size x_cell_size y_cell_size'
29 _, hx, hy = lines[i+2].split()
30 hx = float(hx)
31 hy = float(hy)
32
33 # Read vertex values in the order: left-bottom, right-bottom, left-top, right-top
34 values = [float(value) for value in lines[i+4].split()]
35
36 # Write in the output
37 data.extend([[xlb, ylb, values[0]],
38 [xlb+hx, ylb, values[1]],
39 [xlb, ylb+hy, values[2]],
40 [xlb+hx, ylb+hy, values[3]]])
41
42 # jump to the next 'begin patch'
43 i += 8
44
45 else:
46 i += 1
47
48 # keep only unique rows (one vertex -- one entry)
49 tolerance = 1e-9
50 data_unique = []
51
52 for row in data:
53 # Check if row=[x,y,val] is close to any existing row
54 if not any( np.all(np.isclose(row, unique_row, atol=tolerance)) for unique_row in data_unique ):
55 data_unique.append(row)
56
57 # assert:
58 # size of data = 4*N^2
59 # size of data_unique = (N+1)^2, where N is the number of cells
60 assert np.sqrt(np.shape(data)[0]) == (np.sqrt(np.shape(data_unique)[0]) - 1) * 2, f'{np.shape(data) = }, {np.shape(data_unique) = }'
61 result = np.array(data_unique)
62
63 elif solver_type == 'DG':
64 # For DG, convert the patch file format into a dictionary:
65 # {(x*,y*): [val0, val1, ...], ...}, where
66 # (x*,y*) are the coordinates of the left bottom vertex of the cell and
67 # val0, val1, ... are values assigned to the cell dofs
68
69 result = {}
70
71 i = 0
72 while i < len(lines):
73 if lines[i].startswith("begin patch"):
74 # Read line 'offset x_left_bottom_node_coordinate y_left_bottom_node_coordinate'
75 _, xlb, ylb = lines[i+1].split()
76 # Read values
77 values = [float(value) for value in lines[i+4].split()]
78 result[( float(xlb), float(ylb) )] = values
79
80 # jump to the next 'begin patch'
81 i += 8
82 else:
83 # check next line
84 i += 1
85
86 return result
87
88def reorder_array(array1, array2):
89 """
90 Given array1 and array2 of the same format [x,y,val],
91 rearrange array2 in accordance with the order of coordinates
92 in array1
93 """
94
95 array2_reorder = np.zeros_like(array2)
96
97 for i in range(np.shape(array1)[0]):
98 x = array1[i, 0]
99 y = array1[i, 1]
100 mask = np.isclose(array2[:, 0], x) & np.isclose(array2[:, 1], y)
101 matching_row = array2[mask]
102 array2_reorder[i,:] = matching_row
103
104 #assert np.allclose( array2[:,0:2], array2_reorder[:,0:2] )
105
106 return array2_reorder
107
108def plot_field(data):
109 """
110 Visualise the parsed field as an interactive scatter plot.
111 """
112
113 import matplotlib.pyplot as plt
114 from mpl_toolkits.mplot3d import Axes3D
115
116 x = data[:, 0]
117 y = data[:, 1]
118 val = data[:, 2]
119
120 # Plot
121 fig = plt.figure()
122 ax = fig.add_subplot(111, projection='3d')
123 sc = ax.scatter(x, y, val, c=val, cmap='viridis')
124 fig.colorbar(sc, ax=ax, label='Value')
125 ax.set_xlabel('x')
126 ax.set_ylabel('y')
127 ax.set_zlabel('val')
128 ax.set_title(' ')
129 plt.show()
130
131def plot_field_dg(data, H):
132 """
133 Visualise the parsed field as an interactive scatter plot.
134
135 :arg data: parsed patch data in the form of a dictionary as output of parse_patch_file()
136 :arg H: mesh size as list of cell sizes in each direction: [hx, hy]
137 """
138 import matplotlib.pyplot as plt
139 from mpl_toolkits.mplot3d import Axes3D
140 import mghype
141
142 assert len(H) == 2, "Only works for 2D"
143
144 # For plot
145 fig = plt.figure()
146 ax = fig.add_subplot(111, projection='3d')
147 x = []
148 y = []
149 val = []
150
151 # Local coordinates of cell nodes
152 poly_degree = int(np.sqrt(len(data[(0.0, 0.0)]))) - 1
154 local_node_coordinates = matrices._Xi_C
155 num_of_nodes = len(local_node_coordinates[0])
156
157 # Allocate list of global coordinates
158 global_node_coordinates = [[np.zeros_like(arr) for arr in local_node_coordinates[0]]]
159
160 for key in data.keys():
161 # Coordinates of the left-bottom cell vertex
162 xlb = key[0]
163 ylb = key[1]
164
165 # Local-to-global mapping:
166 # x = xlb + hx/2*(xi + 1)
167 # y = ylb + hy/2*(eta + 1)
168 for i in range(num_of_nodes):
169 global_node_coordinates[0][i][0] = xlb + 0.5 * H[0] * (local_node_coordinates[0][i][0] + 1.0)
170 global_node_coordinates[0][i][1] = ylb + 0.5 * H[1] * (local_node_coordinates[0][i][1] + 1.0)
171 # global_node_coordinates[0][i][:] = [ key[coord_id] + 0.5 * H[coord_id] * (local_node_coordinates[0][i][coord_id] + 1.0) for coord_id in range(2) ]
172
173 # Add to global arrays for plotting
174 x.extend([ global_node_coordinates[0][i][0] for i in range(num_of_nodes) ])
175 y.extend([ global_node_coordinates[0][i][1] for i in range(num_of_nodes) ])
176 val.extend(data[key])
177
178 # Plot
179 sc = ax.scatter(x, y, val, c=val, cmap='viridis')
180 fig.colorbar(sc, ax=ax, label='Value')
181 ax.set_xlabel('x')
182 ax.set_ylabel('y')
183 ax.set_zlabel('val')
184 ax.set_title(' ')
185 #plt.show()
186
187def construct_dg_function(data, H):
188 """
189 Construct exact solution with the same structure as data
190
191 :arg data: parsed patch data in the form of a dictionary as output of parse_patch_file()
192 :arg H: mesh size as list of cell sizes in each direction: [hx, hy]
193 """
194 import matplotlib.pyplot as plt
195 from mpl_toolkits.mplot3d import Axes3D
196 import mghype
197
198 assert len(H) == 2, "Only works for 2D"
199
200 # Create dictionary with the same keys as data and zero values
201 result = {key: [0] * len(value) for key, value in data.items()}
202
203 # Local coordinates of cell nodes
204 poly_degree = int(np.sqrt(len(data[(0.0, 0.0)]))) - 1
206 local_node_coordinates = matrices._Xi_C
207 num_of_nodes = len(local_node_coordinates[0])
208
209 for key in data.keys():
210 # Coordinates of the left-bottom cell vertex
211 xlb = key[0]
212 ylb = key[1]
213
214 # Local-to-global mapping:
215 # x = xlb + hx/2*(xi + 1)
216 # y = ylb + hy/2*(eta + 1)
217 for i in range(num_of_nodes):
218 x_node = xlb + 0.5 * H[0] * (local_node_coordinates[0][i][0] + 1.0)
219 y_node = ylb + 0.5 * H[1] * (local_node_coordinates[0][i][1] + 1.0)
220 result[key][i] = np.sin(2.0*np.pi*x_node) * np.sin(2.0*np.pi*y_node)
221
222 return result
Classical DG discretisation of 2d classical Poisson formulation with spurious facet function spaces.