krafiq commited on
Commit
62d84db
1 Parent(s): 717c335

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +280 -0
app.py ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pickle
2
+ import pandas as pd
3
+ import tensorflow as tf
4
+ from tensorflow.keras.models import load_model
5
+ from collections import Counter
6
+
7
+ # Creating a numpy array of shape (8, 16, 1)
8
+ import cv2
9
+ import numpy as np
10
+ import matplotlib.pyplot as plt
11
+ import gradio as gr
12
+
13
+ flow_field = np.ones((128,256), dtype = np.uint8)
14
+
15
+ # Changing the left input side
16
+ flow_field[:,0] = 3
17
+ # Changing the right output side
18
+ flow_field[:,-1] = 4
19
+ # Changing the top layer
20
+ flow_field[0,:] = 2
21
+ # Changing the bottom layer
22
+ flow_field[-1,:] = 2
23
+
24
+ def nvs_loss(y_pred, rho=10, nu=0.0001): #arbitary rho and nu(Later use values of air)
25
+ u,v,p = tf.split(y_pred, 3, axis=3)
26
+
27
+ #First order derivative
28
+ du_dx, du_dy = tf.image.image_gradients(u) # tf.image.image_gradients returns a tuple containing two tensors: u-grad along the x dir and u-grad along the y dir
29
+ dv_dx, dv_dy = tf.image.image_gradients(v)
30
+ dp_dx, dp_dy = tf.image.image_gradients(p)
31
+
32
+ #Second order derivatives
33
+ du_dx2, du_dydx = tf.image.image_gradients(du_dx) # du_dydx will be unused
34
+ du_dxdy, du_dy2 = tf.image.image_gradients(du_dy) # du_dxdy will be unused
35
+
36
+ dv_dx2, dv_dydx = tf.image.image_gradients(dv_dx)
37
+ dv_dxdy, dv_dy2 = tf.image.image_gradients(dv_dy)
38
+
39
+ #Momentum equation
40
+ er1_tensor = tf.math.multiply(u, du_dx) + tf.math.multiply(v, du_dy) + 1.0*dp_dx/rho - nu*(du_dx2 + du_dy2)
41
+ er2_tensor = tf.math.multiply(u, dv_dx) + tf.math.multiply(v, dv_dy) + 1.0*dp_dy/rho - nu*(dv_dx2 + dv_dy2)
42
+
43
+ # # #Continuity equation
44
+ er3_tensor = du_dx + dv_dy
45
+
46
+ er1 = tf.reduce_mean(er1_tensor)
47
+ er2 = tf.reduce_mean(er2_tensor)
48
+ er3 = tf.reduce_mean(er3_tensor)
49
+
50
+ return er1*er1 + er2*er2 + er3*er3
51
+
52
+ # Initiating the Loss Function-
53
+ def custom_loss(y_true, y_pred):
54
+ nv_loss = nvs_loss(y_pred)
55
+ mse_loss = tf.reduce_mean(tf.square(y_true-y_pred)) # Try mse loss function here
56
+ return mse_loss + nv_loss
57
+
58
+ import torch
59
+ import matplotlib
60
+ def colorize(value, vmin=None, vmax=None, cmap='gray_r', invalid_val=-99, invalid_mask=None, background_color=(128, 128, 128, 255), gamma_corrected=False, value_transform=None):
61
+ """Converts a depth map to a color image.
62
+
63
+ Args:
64
+ value (torch.Tensor, numpy.ndarry): Input depth map. Shape: (H, W) or (1, H, W) or (1, 1, H, W). All singular dimensions are squeezed
65
+ vmin (float, optional): vmin-valued entries are mapped to start color of cmap. If None, value.min() is used. Defaults to None.
66
+ vmax (float, optional): vmax-valued entries are mapped to end color of cmap. If None, value.max() is used. Defaults to None.
67
+ cmap (str, optional): matplotlib colormap to use. Defaults to 'magma_r'.
68
+ invalid_val (int, optional): Specifies value of invalid pixels that should be colored as 'background_color'. Defaults to -99.
69
+ invalid_mask (numpy.ndarray, optional): Boolean mask for invalid regions. Defaults to None.
70
+ background_color (tuple[int], optional): 4-tuple RGB color to give to invalid pixels. Defaults to (128, 128, 128, 255).
71
+ gamma_corrected (bool, optional): Apply gamma correction to colored image. Defaults to False.
72
+ value_transform (Callable, optional): Apply transform function to valid pixels before coloring. Defaults to None.
73
+
74
+ Returns:
75
+ numpy.ndarray, dtype - uint8: Colored depth map. Shape: (H, W, 4)
76
+ """
77
+ if isinstance(value, torch.Tensor):
78
+ value = value.detach().cpu().numpy()
79
+
80
+ value = value.squeeze()
81
+ if invalid_mask is None:
82
+ invalid_mask = value == invalid_val
83
+ mask = np.logical_not(invalid_mask)
84
+
85
+ # normalize
86
+ # vmin = np.percentile(value[mask],2) if vmin is None else vmin
87
+ # vmax = np.percentile(value[mask],85) if vmax is None else vmax
88
+ vmin = np.min(value[mask]) if vmin is None else vmin
89
+ vmax = np.max(value[mask]) if vmax is None else vmax
90
+ if vmin != vmax:
91
+ value = (value - vmin) / (vmax - vmin) # vmin..vmax
92
+ else:
93
+ # Avoid 0-division
94
+ value = value * 0.
95
+
96
+ # squeeze last dim if it exists
97
+ # grey out the invalid values
98
+
99
+ value[invalid_mask] = np.nan
100
+ cmapper = matplotlib.cm.get_cmap(cmap)
101
+ if value_transform:
102
+ value = value_transform(value)
103
+ # value = value / value.max()
104
+ value = cmapper(value, bytes=True) # (nxmx4)
105
+
106
+ # img = value[:, :, :]
107
+ img = value[...]
108
+ img[invalid_mask] = background_color
109
+
110
+ # return img.transpose((2, 0, 1))
111
+ if gamma_corrected:
112
+ # gamma correction
113
+ img = img / 255
114
+ img = np.power(img, 2.2)
115
+ img = img * 255
116
+ img = img.astype(np.uint8)
117
+ return img
118
+
119
+ def img_preprocess(image, h, w):
120
+ # Convert the drawn image to grayscale
121
+ img_gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
122
+
123
+ # Threshold the grayscale image to create a binary image
124
+ _, binary_img = cv2.threshold(img_gray, 1, 255, cv2.THRESH_BINARY)
125
+
126
+ # Perform flood fill starting from a point inside the shape. Fill the inside with pixel value 0
127
+ seed_point = (int(h/2), int(w/2))
128
+ retval, flooded_image, mask, rect = cv2.floodFill(binary_img, None, seed_point, 0)
129
+ flooded_image = (flooded_image/255).astype(np.uint8)
130
+ return flooded_image
131
+
132
+ def patch_stiching(flooded_image, h, w, x0, y0): # ((x0, y0) = center of channel, (w1, h1) = height and width of patch)
133
+ flow_field_updated = np.copy(flow_field)
134
+ print('flow field updated - ', flow_field_updated[:,-1])
135
+ flow_field_updated[int(x0-w/2):int(x0+w/2),int(y0-h/2):int(y0+h/2)] = flooded_image
136
+
137
+
138
+ # flow_field_updated is the main thing that we will use to make our predictions on -
139
+ test_img = np.expand_dims(flow_field_updated, axis = 0)
140
+ test_img = np.expand_dims(test_img, axis = 3) # Shape of test_img = (1, 128, 256)
141
+ return test_img
142
+
143
+ # Define grid points
144
+ x_points = np.linspace(0, 255, 256)
145
+ y_points = np.linspace(0, 127, 128)
146
+ X, Y = np.meshgrid(x_points, y_points)
147
+
148
+ def return_quiver_plot(u, v):
149
+ velocity = np.sqrt(u**2 + v**2)
150
+ ax = plt.subplot()
151
+ ax.imshow(velocity, origin = 'lower', extent = (0,256, 0,128), cmap = 'gray')
152
+ q = ax.quiver(X[5::8,5::8], Y[5::8,5::8], u[5::8,5::8], u[5::8,5::8], pivot = 'middle', color = 'red')
153
+ # ax.quiverkey(q, X=0.9, Y=1.05, U=2,
154
+ # label='m/s', labelpos='E')
155
+ # plt.title("Velocity distribution")
156
+ # plt.show()
157
+ return q
158
+
159
+ def squeeze_function(img):
160
+ img = np.squeeze(img, axis = 0)
161
+ img = np.squeeze(img, axis = 2)
162
+ return img
163
+
164
+ # Taking a shape from the user on sketchpad and placing it inside the fluid flow -
165
+
166
+ h, w = 48, 48 # patch_size in which the obstacle will be drawn
167
+ x0, y0 = 64, 128 # (x0, y0) = center of channel
168
+
169
+ def fill_shape_with_pixels(img): #img is taken by gradio as uint8
170
+ if img is None:
171
+ return np.zeros((h, w), dtype=np.uint8) # "No input sketch"
172
+ # Calling the the flooded image function to fill inside the obstacle
173
+ flooded_image = img_preprocess(img, h, w)
174
+ # Performing patch statching to put the obstacle at the required center position
175
+ test_img = patch_stiching(flooded_image, h, w, x0, y0)
176
+
177
+ # Loading and Compiling the Model
178
+ model_path = "/content/drive/MyDrive/Pinns_Loss_file.h5"
179
+ model = load_model(model_path, compile = False)
180
+ model.compile(loss=custom_loss, optimizer=tf.keras.optimizers.AdamW(learning_rate = 0.0001), metrics=['mae', 'cosine_proximity'])
181
+
182
+ # Making Model prediction from input sketch shape
183
+ prediction = model.predict(test_img) # (prediction.shape = (1, 128, 256, 3))
184
+ u_pred, v_pred, p_pred = np.split(prediction, 3, axis=3) # shape of u_pred, v_pred, p_pred = (1, 128, 256, 1)
185
+
186
+ # Making test_img in shape required by zero_pixel_location
187
+ req_img = squeeze_function(test_img)
188
+
189
+ # Storing the location of 0 pixel values
190
+ #req_img = req_img.astype(int)
191
+ zero_pixel_locations = np.argwhere(req_img == 0)
192
+
193
+ # Reducing the dimensions-
194
+ u_profile = u_pred[0][:,:,0] # shape of u profile to compatible shape (H, W) = (128, 256)
195
+ v_profile = v_pred[0][:,:,0]
196
+ p_profile = p_pred[0][:,:,0]
197
+ p_profile[p_profile>1.6] = 1.6
198
+
199
+ # Creating a copy of the above profiles-
200
+ u_profile_dash = np.copy(u_profile)
201
+ v_profile_dash = np.copy(v_profile)
202
+
203
+ # Creating a copy of the above profiles-
204
+ u_profile_dash_1 = np.copy(u_profile)
205
+ v_profile_dash_1 = np.copy(v_profile)
206
+
207
+
208
+ # Hollowing the obstacle out from the u and v plots. Origin of imae is lop left and origin of plot is top right
209
+ for y, x in zero_pixel_locations:
210
+ u_profile_dash[128 - y, x] = 0
211
+ v_profile_dash[128 - y, x] = 0
212
+ # will be used for image
213
+ u_profile_dash_1[y, x] = 0
214
+ v_profile_dash_1[y, x] = 0
215
+
216
+
217
+ # Quiver Plot
218
+ quiver_plot = plt.figure(figsize = (14,6), edgecolor = "gray")
219
+ velocity = np.sqrt(u_profile_dash_1**2 + v_profile_dash_1**2)
220
+ ax = plt.subplot()
221
+ ax.imshow(velocity, cmap = 'gray', extent = (0,256, 0,128))
222
+ q = ax.quiver(X[5::7,5::7], Y[5::7,5::7], u_profile_dash[5::7,5::7], v_profile_dash[5::7,5::7], pivot = 'middle', color = 'red')
223
+ ax.quiverkey(q, X=0.9, Y=1.07, U=2,
224
+ label='m/s', labelpos='E')
225
+ plt.title("Velocity distribution", fontsize = 11)
226
+ plt.xlabel("Length of Channel", fontsize = 11)
227
+ plt.ylabel("Height of Channel", fontsize = 11)
228
+
229
+ # StreamLine Plot
230
+ streamline_plot = plt.figure(figsize = (14,6), edgecolor = "gray")
231
+ plt.streamplot(X, Y, u_profile_dash, v_profile_dash, density = 3.5)
232
+ plt.axis('scaled')
233
+ plt.title("Streamline Plot", fontsize = 11)
234
+ plt.xlabel("Length of Channel", fontsize = 11)
235
+ plt.ylabel("Height of Channel", fontsize = 11)
236
+
237
+ # Colorize taken from ZoeDepth Model
238
+ u_colored = colorize(u_profile, cmap = 'jet')
239
+ #cbar_u = plt.colorbar(u_profile,fraction=0.025, pad=0.05)
240
+ v_colored = colorize(v_profile, cmap = 'jet')
241
+ #cbar_v = plt.colorbar(v_colored,fraction=0.025, pad=0.05)
242
+ p_colored = colorize(p_profile, cmap = 'jet')
243
+ #cbar_p = plt.colorbar(p_colored,fraction=0.025, pad=0.05)
244
+
245
+
246
+ return colorize(req_img, cmap = 'jet'), quiver_plot, streamline_plot, u_colored, v_colored, p_colored
247
+
248
+ # Importing gr.Blocks()
249
+
250
+ with gr.Blocks(theme="Taithrah/Minimal") as demo:
251
+ gr.Markdown(
252
+ """
253
+ # Physics Constrained DNN for Predicting Mean Turbulent Flows
254
+ The App solves 2-D incompressible steady state NS equations for any given 2-D closed geometry. Geometry needs to be drawn around the center of the patch.\n
255
+ It predicts the streamlines,horizontal & vertical velocity profiles and the pressure profiles using a hybrid loss function.\n
256
+ """)
257
+ with gr.Row():
258
+ with gr.Column():
259
+ input_sketch = gr.Image(label = "Draw any Obstacle contour around the patch center",
260
+ tool="sketch", source="canvas", shape=(h, w), brush_radius = 3)
261
+ Process_button = gr.Button("Process Flow Parameters")
262
+
263
+ with gr.Column():
264
+ filled_channel = gr.Image(label = "Drawn object inside a Channel of dimensions 128*256", container = True)
265
+
266
+ with gr.Row():
267
+ quiver_plot = gr.Plot(label = "Velocity Distribution Around The Obstacle", scale = 2)
268
+
269
+ with gr.Row():
270
+ streamline_plot = gr.Plot(label = "Stream Lines Around The Obstacle", scale = 2)
271
+
272
+ with gr.Row():
273
+ u_image = gr.Image(label = "Horizontal Velocity")
274
+ v_image = gr.Image(label = "Vertical Velocity")
275
+ p_image = gr.Image(label = "Pressure")
276
+
277
+
278
+ Process_button.click(fn=fill_shape_with_pixels, inputs=input_sketch, outputs=[filled_channel, quiver_plot, streamline_plot, u_image, v_image, p_image])
279
+
280
+ demo.launch(debug=True, server_name = "0.0.0.0", share = True, inline = False)