jithin14 commited on
Commit
81efd79
·
0 Parent(s):

Initial commit without model file

Browse files
Files changed (7) hide show
  1. .gitattributes +1 -0
  2. Dockerfile +22 -0
  3. README.md +35 -0
  4. app.py +348 -0
  5. conf/arch/fourier_net.yaml +8 -0
  6. conf/config.yaml +82 -0
  7. requirements.txt +3 -0
.gitattributes ADDED
@@ -0,0 +1 @@
 
 
1
+ *.pth filter=lfs diff=lfs merge=lfs -text
Dockerfile ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM nvcr.io/nvidia/modulus/modulus:24.12
2
+
3
+ # Install additional dependencies
4
+ COPY requirements.txt /workspace/requirements.txt
5
+ RUN pip install -r /workspace/requirements.txt
6
+
7
+ # Copy application files
8
+ COPY app.py /workspace/
9
+ COPY conf /workspace/conf/
10
+ COPY outputs/main/flow_network.0.pth /workspace/outputs/main/
11
+
12
+ # Set working directory
13
+ WORKDIR /workspace
14
+
15
+ # Expose Streamlit port
16
+ EXPOSE 8501
17
+
18
+ # Set environment variable to disable CUDA
19
+ ENV CUDA_VISIBLE_DEVICES=""
20
+
21
+ # Command to run the Streamlit app
22
+ CMD ["streamlit", "run", "app.py", "--server.address", "0.0.0.0"]
README.md ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 3D Wind Flow Around Building Visualization
2
+
3
+ This interactive application demonstrates computational fluid dynamics (CFD) simulation of wind flow around a parameterized building using deep learning. The model was trained using NVIDIA Modulus to solve the Navier-Stokes equations with turbulence modeling.
4
+
5
+ ## Features
6
+
7
+ - **Real-time Visualization**: Instantly see how wind flows around buildings of different sizes and positions
8
+ - **Interactive Parameters**:
9
+ - Building position (X, Y)
10
+ - Building dimensions (width, depth, height)
11
+ - **Multiple Views**:
12
+ - Velocity magnitude at mid-height
13
+ - Pressure distribution
14
+ - 3D streamlines showing flow patterns
15
+
16
+ ## Technical Details
17
+
18
+ - **Physics**: 3D steady-state Navier-Stokes with turbulence model
19
+ - **Domain**: [0,10] x [0,5] x [0,5] meters
20
+ - **Inlet Conditions**: 10 m/s uniform flow
21
+ - **Model**: FourierNet trained using NVIDIA Modulus
22
+ - **Hardware**: GPU-accelerated inference
23
+
24
+ ## How to Use
25
+
26
+ 1. Use the sliders in the sidebar to adjust building parameters
27
+ 2. The visualizations will update in real-time:
28
+ - Top left: Velocity magnitude contour
29
+ - Top right: Pressure distribution
30
+ - Bottom: 3D streamlines with building geometry
31
+ 3. You can rotate and zoom the 3D view using your mouse
32
+
33
+ ## About
34
+
35
+ This demo showcases the application of deep learning to computational fluid dynamics, enabling real-time prediction of complex flow fields. The model was trained on parametric building geometries to understand flow patterns and pressure distributions around buildings of varying sizes and positions.
app.py ADDED
@@ -0,0 +1,348 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import torch
3
+ import numpy as np
4
+ from omegaconf import OmegaConf
5
+ from modulus.sym.hydra import instantiate_arch
6
+ from modulus.sym.key import Key
7
+ import plotly.graph_objects as go
8
+ from pathlib import Path
9
+
10
+ # Configure page and cache settings
11
+ st.set_page_config(page_title="3D Wind Flow Visualization", layout="wide")
12
+ st.title("Interactive 3D Wind Flow Around Building")
13
+
14
+ # Load configuration
15
+ @st.cache_resource
16
+ def load_config():
17
+ cfg = OmegaConf.load('conf/config.yaml')
18
+ return cfg.arch.fourier_net
19
+
20
+ # Initialize model
21
+ @st.cache_resource
22
+ def load_model():
23
+ # Create flow network
24
+ flow_net = instantiate_arch(
25
+ input_keys=[
26
+ Key("x"), Key("y"), Key("z"),
27
+ Key("bld_x"), Key("bld_y"),
28
+ Key("bld_width"), Key("bld_depth"), Key("bld_height"),
29
+ ],
30
+ output_keys=[Key("u"), Key("v"), Key("w"), Key("p")],
31
+ cfg=load_config(),
32
+ )
33
+
34
+ # Load trained weights and ensure CPU mode
35
+ state_dict = torch.load('outputs/main/flow_network.0.pth', map_location=torch.device('cpu'))
36
+ flow_net.load_state_dict(state_dict)
37
+ flow_net.eval() # Set to evaluation mode
38
+ return flow_net
39
+
40
+ try:
41
+ model = load_model()
42
+ except Exception as e:
43
+ st.error(f"Error loading model: {str(e)}")
44
+ st.stop()
45
+
46
+ # Create sidebar with building parameters
47
+ st.sidebar.header("Building Parameters")
48
+ bld_x = st.sidebar.slider("Building X Position", 2.0, 6.0, 4.0, 0.1)
49
+ bld_y = st.sidebar.slider("Building Y Position", 1.0, 4.0, 2.5, 0.1)
50
+ bld_width = st.sidebar.slider("Building Width", 0.5, 2.0, 1.0, 0.1)
51
+ bld_depth = st.sidebar.slider("Building Depth", 0.5, 1.5, 1.0, 0.1)
52
+ bld_height = st.sidebar.slider("Building Height", 1.0, 2.5, 1.5, 0.1)
53
+
54
+ # Create grid for visualization (reduced resolution for CPU)
55
+ @st.cache_data
56
+ def create_grid():
57
+ x = np.linspace(0, 10, 30) # Reduced from 50
58
+ y = np.linspace(0, 5, 15) # Reduced from 25
59
+ z = np.linspace(0, 5, 15) # Reduced from 25
60
+ return np.meshgrid(x, y, z, indexing='ij')
61
+
62
+ X, Y, Z = create_grid()
63
+
64
+ # Batch processing for CPU efficiency
65
+ def predict_flow(x, y, z, bld_params, batch_size=5000):
66
+ try:
67
+ # Prepare input grid
68
+ xyz = torch.tensor(np.stack([x.flatten(), y.flatten(), z.flatten()], axis=1), dtype=torch.float32)
69
+ num_points = len(xyz)
70
+
71
+ # Initialize output arrays
72
+ u_out = np.zeros(num_points)
73
+ v_out = np.zeros(num_points)
74
+ w_out = np.zeros(num_points)
75
+ p_out = np.zeros(num_points)
76
+
77
+ # Process in batches
78
+ for i in range(0, num_points, batch_size):
79
+ batch_end = min(i + batch_size, num_points)
80
+ batch_xyz = xyz[i:batch_end]
81
+
82
+ # Create input dictionary for batch
83
+ inputs = {
84
+ "x": batch_xyz[:, 0:1],
85
+ "y": batch_xyz[:, 1:2],
86
+ "z": batch_xyz[:, 2:3],
87
+ "bld_x": torch.full((batch_end-i, 1), bld_params[0], dtype=torch.float32),
88
+ "bld_y": torch.full((batch_end-i, 1), bld_params[1], dtype=torch.float32),
89
+ "bld_width": torch.full((batch_end-i, 1), bld_params[2], dtype=torch.float32),
90
+ "bld_depth": torch.full((batch_end-i, 1), bld_params[3], dtype=torch.float32),
91
+ "bld_height": torch.full((batch_end-i, 1), bld_params[4], dtype=torch.float32)
92
+ }
93
+
94
+ # Make prediction
95
+ with torch.no_grad():
96
+ outputs = model(inputs)
97
+
98
+ # Store batch results
99
+ u_out[i:batch_end] = outputs["u"].numpy().flatten()
100
+ v_out[i:batch_end] = outputs["v"].numpy().flatten()
101
+ w_out[i:batch_end] = outputs["w"].numpy().flatten()
102
+ p_out[i:batch_end] = outputs["p"].numpy().flatten()
103
+
104
+ # Reshape outputs
105
+ u = u_out.reshape(x.shape)
106
+ v = v_out.reshape(x.shape)
107
+ w = w_out.reshape(x.shape)
108
+ p = p_out.reshape(x.shape)
109
+
110
+ return u, v, w, p
111
+ except Exception as e:
112
+ st.error(f"Error in prediction: {str(e)}")
113
+ return None, None, None, None
114
+
115
+ # Add a progress indicator
116
+ progress_text = st.empty()
117
+ progress_text.text("Computing flow field...")
118
+
119
+ # Make prediction
120
+ bld_params = np.array([bld_x, bld_y, bld_width, bld_depth, bld_height])
121
+ u, v, w, p = predict_flow(X, Y, Z, bld_params)
122
+
123
+ if u is None:
124
+ st.error("Failed to make prediction. Please check the model and parameters.")
125
+ st.stop()
126
+
127
+ progress_text.text("Visualization ready!")
128
+
129
+ # Create visualization
130
+ col1, col2 = st.columns(2)
131
+
132
+ with col1:
133
+ st.subheader("Velocity Magnitude (Slice at Z=2.5m)")
134
+ z_slice_idx = len(Z[0,0]) // 2
135
+
136
+ vel_mag = np.sqrt(u[:,:,z_slice_idx]**2 + v[:,:,z_slice_idx]**2 + w[:,:,z_slice_idx]**2)
137
+
138
+ # Create building rectangle for the plot
139
+ building_x = [bld_x, bld_x + bld_width, bld_x + bld_width, bld_x, bld_x]
140
+ building_y = [bld_y, bld_y, bld_y + bld_depth, bld_y + bld_depth, bld_y]
141
+
142
+ fig = go.Figure()
143
+
144
+ # Add velocity magnitude contour
145
+ fig.add_trace(go.Contour(
146
+ x=X[:,0,0],
147
+ y=Y[0,:,0],
148
+ z=vel_mag.T,
149
+ colorscale='Viridis',
150
+ colorbar=dict(title='Velocity (m/s)'),
151
+ ))
152
+
153
+ # Add building outline
154
+ fig.add_trace(go.Scatter(
155
+ x=building_x,
156
+ y=building_y,
157
+ mode='lines',
158
+ line=dict(color='red', width=2),
159
+ name='Building'
160
+ ))
161
+
162
+ fig.update_layout(
163
+ xaxis_title="X (m)",
164
+ yaxis_title="Y (m)",
165
+ width=600,
166
+ height=400
167
+ )
168
+
169
+ st.plotly_chart(fig)
170
+
171
+ with col2:
172
+ st.subheader("Pressure Distribution (Slice at Z=2.5m)")
173
+
174
+ fig = go.Figure()
175
+
176
+ # Add pressure contour
177
+ fig.add_trace(go.Contour(
178
+ x=X[:,0,0],
179
+ y=Y[0,:,0],
180
+ z=p[:,:,z_slice_idx].T,
181
+ colorscale='RdBu',
182
+ colorbar=dict(title='Pressure'),
183
+ ))
184
+
185
+ # Add building outline
186
+ fig.add_trace(go.Scatter(
187
+ x=building_x,
188
+ y=building_y,
189
+ mode='lines',
190
+ line=dict(color='red', width=2),
191
+ name='Building'
192
+ ))
193
+
194
+ fig.update_layout(
195
+ xaxis_title="X (m)",
196
+ yaxis_title="Y (m)",
197
+ width=600,
198
+ height=400
199
+ )
200
+
201
+ st.plotly_chart(fig)
202
+
203
+ # Add streamlines visualization
204
+ st.subheader("3D Streamlines")
205
+
206
+ # Downsample for streamlines
207
+ skip = 3
208
+ X_sub = X[::skip,::skip,::skip]
209
+ Y_sub = Y[::skip,::skip,::skip]
210
+ Z_sub = Z[::skip,::skip,::skip]
211
+ u_sub = u[::skip,::skip,::skip]
212
+ v_sub = v[::skip,::skip,::skip]
213
+ w_sub = w[::skip,::skip,::skip]
214
+
215
+ # Function to interpolate velocity at any point
216
+ def interpolate_velocity(x, y, z):
217
+ # Find indices
218
+ ix = np.clip(int((x / 10.0) * (len(X)-1)), 0, len(X)-2)
219
+ iy = np.clip(int((y / 5.0) * (len(Y[0])-1)), 0, len(Y[0])-2)
220
+ iz = np.clip(int((z / 5.0) * (len(Z[0,0])-1)), 0, len(Z[0,0])-2)
221
+
222
+ return u[ix,iy,iz], v[ix,iy,iz], w[ix,iy,iz]
223
+
224
+ # Function to compute streamline
225
+ def compute_streamline(x_start, y_start, z_start, num_steps=50, dt=0.1):
226
+ streamline_x = [x_start]
227
+ streamline_y = [y_start]
228
+ streamline_z = [z_start]
229
+
230
+ x, y, z = x_start, y_start, z_start
231
+
232
+ for _ in range(num_steps):
233
+ # Get velocity at current point
234
+ u_val, v_val, w_val = interpolate_velocity(x, y, z)
235
+
236
+ # Update position using RK4
237
+ x_new = x + u_val * dt
238
+ y_new = y + v_val * dt
239
+ z_new = z + w_val * dt
240
+
241
+ # Check if point is inside domain and outside building
242
+ if (0 <= x_new <= 10 and 0 <= y_new <= 5 and 0 <= z_new <= 5 and
243
+ not (bld_x <= x_new <= bld_x + bld_width and
244
+ bld_y <= y_new <= bld_y + bld_depth and
245
+ 0 <= z_new <= bld_height)):
246
+ streamline_x.append(x_new)
247
+ streamline_y.append(y_new)
248
+ streamline_z.append(z_new)
249
+ x, y, z = x_new, y_new, z_new
250
+ else:
251
+ break
252
+
253
+ return streamline_x, streamline_y, streamline_z
254
+
255
+ # Create streamlines using plotly
256
+ fig = go.Figure()
257
+
258
+ # Add streamlines from inlet
259
+ num_streamlines = 20
260
+ y_starts = np.linspace(0.5, 4.5, num_streamlines)
261
+ z_starts = np.linspace(0.5, 4.5, num_streamlines)
262
+
263
+ # Add streamlines from different starting positions
264
+ for y_start in y_starts[::2]: # Skip some to reduce density
265
+ for z_start in z_starts[::2]: # Skip some to reduce density
266
+ # Skip if starting point would be inside building
267
+ if (bld_x <= 0 <= bld_x + bld_width and
268
+ bld_y <= y_start <= bld_y + bld_depth and
269
+ 0 <= z_start <= bld_height):
270
+ continue
271
+
272
+ x_start = 0.1 # Start slightly inside domain
273
+ streamline_x, streamline_y, streamline_z = compute_streamline(x_start, y_start, z_start)
274
+
275
+ # Color based on velocity magnitude
276
+ velocities = []
277
+ for i in range(len(streamline_x)):
278
+ u_val, v_val, w_val = interpolate_velocity(streamline_x[i], streamline_y[i], streamline_z[i])
279
+ velocities.append(np.sqrt(u_val**2 + v_val**2 + w_val**2))
280
+
281
+ # Create streamline
282
+ fig.add_trace(go.Scatter3d(
283
+ x=streamline_x,
284
+ y=streamline_y,
285
+ z=streamline_z,
286
+ mode='lines',
287
+ line=dict(
288
+ color=velocities,
289
+ colorscale='Viridis',
290
+ width=3
291
+ ),
292
+ showlegend=False
293
+ ))
294
+
295
+ # Add building
296
+ building_vertices = [
297
+ [bld_x, bld_y, 0], # 0: front bottom left
298
+ [bld_x + bld_width, bld_y, 0], # 1: front bottom right
299
+ [bld_x + bld_width, bld_y + bld_depth, 0], # 2: back bottom right
300
+ [bld_x, bld_y + bld_depth, 0], # 3: back bottom left
301
+ [bld_x, bld_y, bld_height], # 4: front top left
302
+ [bld_x + bld_width, bld_y, bld_height], # 5: front top right
303
+ [bld_x + bld_width, bld_y + bld_depth, bld_height], # 6: back top right
304
+ [bld_x, bld_y + bld_depth, bld_height] # 7: back top left
305
+ ]
306
+
307
+ # Define faces using indices
308
+ i = [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4] # First vertex of each triangle
309
+ j = [1, 2, 4, 1, 5, 2, 6, 3, 7, 2, 5, 7] # Second vertex of each triangle
310
+ k = [2, 3, 5, 4, 6, 6, 7, 7, 6, 6, 6, 6] # Third vertex of each triangle
311
+
312
+ fig.add_trace(go.Mesh3d(
313
+ x=[v[0] for v in building_vertices],
314
+ y=[v[1] for v in building_vertices],
315
+ z=[v[2] for v in building_vertices],
316
+ i=i,
317
+ j=j,
318
+ k=k,
319
+ color='red',
320
+ opacity=0.5,
321
+ name='Building'
322
+ ))
323
+
324
+ fig.update_layout(
325
+ scene=dict(
326
+ xaxis_title="X (m)",
327
+ yaxis_title="Y (m)",
328
+ zaxis_title="Z (m)",
329
+ aspectmode='data',
330
+ camera=dict(
331
+ up=dict(x=0, y=0, z=1),
332
+ center=dict(x=0, y=0, z=0),
333
+ eye=dict(x=1.5, y=1.5, z=1.5)
334
+ )
335
+ ),
336
+ width=1200,
337
+ height=600
338
+ )
339
+
340
+ st.plotly_chart(fig)
341
+
342
+ st.sidebar.markdown("""
343
+ ### Instructions
344
+ 1. Use the sliders to adjust building parameters
345
+ 2. The top plots show velocity and pressure at mid-height
346
+ 3. The bottom plot shows 3D streamlines around the building
347
+ 4. Red box represents the building
348
+ """)
conf/arch/fourier_net.yaml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ fourier_net:
2
+ arch_type: fourier
3
+ input_key_dims: [3, 5] # (x, y, z) + 5 building parameters
4
+ output_key_dims: [3, 1] # (u, v, w) + p
5
+ layer_size: 512
6
+ num_layers: 6
7
+ activation_fn: silu
8
+ weight_norm: true
conf/config.yaml ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ defaults:
2
+ - modulus_default
3
+ - arch:
4
+ - fourier_net
5
+ - optimizer: adam
6
+ - scheduler: tf_exponential_lr
7
+ - loss: sum
8
+ - _self_
9
+
10
+ jit: false
11
+ save_filetypes: "vtk"
12
+
13
+ custom:
14
+ parameterized: true
15
+ turbulent: true
16
+
17
+ ################################################################################
18
+ # ARCHITECTURE
19
+ ################################################################################
20
+ arch:
21
+ fourier_net:
22
+ arch_type: "fourier"
23
+ _target_: "modulus.sym.models.fourier_net.FourierNetArch"
24
+
25
+ # Input/Output dims
26
+ input_key_dims: [3, 5] # (x,y,z) + (bld_x,bld_y,bld_width,bld_depth,bld_height)
27
+ output_key_dims: [3, 1] # (u,v,w) + p
28
+
29
+ layer_size: 256
30
+ num_layers: 4
31
+ activation_fn: silu
32
+ weight_norm: true
33
+ adaptive_activations: false
34
+
35
+ ################################################################################
36
+ # OPTIMIZER
37
+ ################################################################################
38
+ optimizer:
39
+ lr: 0.001
40
+ betas: [0.9, 0.999]
41
+ eps: 1.0e-8
42
+ weight_decay: 1.0e-5
43
+
44
+ ################################################################################
45
+ # SCHEDULER
46
+ ################################################################################
47
+ scheduler:
48
+ decay_rate: 0.98
49
+ decay_steps: 1000
50
+
51
+ ################################################################################
52
+ # LOSS
53
+ ################################################################################
54
+ loss:
55
+ weights:
56
+ inlet: 20.0 # Strongly enforce inlet conditions
57
+ outlet: 5.0 # Increased to better maintain outflow
58
+ no_slip_building: 5.0 # Keep building interaction
59
+ top: 0.5 # Further reduced wall influence
60
+ ground: 0.5 # Further reduced wall influence
61
+ sides_y0: 0.5 # Further reduced wall influence
62
+ sides_y5: 0.5 # Further reduced wall influence
63
+ interior: 10.0 # Strongly enforce momentum equations in interior
64
+
65
+ ################################################################################
66
+ # TRAINING
67
+ ################################################################################
68
+ training:
69
+ max_steps: 40000
70
+ rec_results_freq: 100
71
+ rec_constraint_freq: 5000
72
+ save_network_freq: 5000
73
+
74
+ ################################################################################
75
+ # BATCH SIZES
76
+ ################################################################################
77
+ batch_size:
78
+ inlet: 1024
79
+ outlet: 1024
80
+ no_slip_building: 2048
81
+ slip: 1024
82
+ interior: 4096
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ streamlit==1.24.0
2
+ plotly==5.15.0
3
+ pyvista==0.39.1