Pendahuluan
Proyek ini mengembangkan model kecerdasan buatan berbasis Physics-Informed Neural Networks (PINN) untuk memprediksi perilaku aliran fluida dalam konfigurasi lid-driven cavity. Alih-alih mengandalkan sepenuhnya pada persamaan Navier-Stokes dalam solver konvensional, pendekatan ini bermaksud melatih jaringan neural untuk memahami pola distribusi kecepatan dan tekanan dengan tetap mempertahankan kesesuaian fisika yang mendasarinya.
Kami memulai dengan melakukan simulasi menggunakan software CFDSOF untuk menghasilkan data referensi yang kemudian digunakan untuk melatih model AI kami.
Spesifikasi Aliran dan Geometri
Karakteristik aliran yang dimodelkan meliputi:
- Sifat aliran: Incompressible, steady-state, turbulent, dan isothermal
- Geometri: Cavity 2D dengan dimensi 0.1m ร 0.1m
- Bilangan Reynolds: 517.2 (termasuk kategori aliran turbulent)
Kondisi batas yang diterapkan:
- Dinding atas bergerak dengan kecepatan konstan 0.1 m/s ke arah kanan
- Dinding bagian lain (kiri, kanan, dan bawah) bersifat no-slip (tidak bergerak)
Parameter fluida yang digunakan:
- Densitas: 1293 kg/mยณ
- Viskositas: 2.5 ร 10โปโต kg/mยทs
Metodologi
Metode penelitian dilaksanakan dalam beberapa tahap:
- Simulasi CFD Menggunakan software CFDSOF, kami menjalankan simulasi untuk mendapatkan data referensi, meliputi:
- Kontur dan vektor kecepatan (komponen U dan V)
- Magnitud kecepatan
- Pola streamline
- Viskositas turbulen efektif
- Tekanan statik
- Ekstraksi Data Data numerik diperoleh melalui menu “lihat alfa” dan “pilih variabel” untuk mendapatkan nilai-nilai yang diperlukan sebagai dasar pelatihan model AI.
- Pengembangan Model PINN Model Physics-Informed Neural Network diimplementasikan dengan Python dan TensorFlow dengan arsitektur:
- Input: koordinat posisi (x, y)
- Output: komponen kecepatan u dan v, serta tekanan p
- Struktur jaringan: 2 hidden layers dengan 32 neuron per layer
- Fungsi aktivasi: tanh
- Optimizer: Adam dengan learning rate 0.001
- Fungsi Loss Model dioptimalkan berdasarkan kombinasi dua jenis loss:
- Physics Loss: Didasarkan pada persamaan kontinuitas dan momentum Navier-Stokes
- Data Loss: Selisih kuadrat antara prediksi model dan data simulasi CFD
- Pelatihan Model Model dilatih selama 1000 epoch menggunakan 10.000 titik domain yang dibangkitkan secara acak dalam geometri cavity.
Hasil Simulasi CFD
Simulasi menghasilkan beragam visualisasi dan dataset, termasuk:
- Data distribusi densitas, turbulensi, dan viskositas efektif
- Profil tekanan statik di seluruh domain
- Pola kecepatan pada arah U (horizontal) dan V (vertikal)
- Magnitud kecepatan yang menggambarkan intensitas aliran
- Pola streamline yang menunjukkan jalur partikel fluida
Visualisasi ini memberikan gambaran komprehensif tentang karakteristik aliran dalam cavity dan menjadi dasar untuk validasi model PINN.
Implementasi Kode
Kode Python untuk model PINN mengimplementasikan arsitektur neural network yang telah dijelaskan. Beberapa komponen utama dalam implementasi meliputi:
- Kelas LidDrivenCavityPINN yang mencakup definisi model, fungsi prediksi, dan logika pelatihan
- Fungsi untuk membangkitkan mesh cavity dan memvisualisasikan hasil
- Penerapan kondisi batas, terutama untuk dinding atas yang bergerak
- Pemrosesan data CFD sebagai referensi pelatihan
- Visualisasi hasil simulasi PINN dibandingkan dengan data CFD
Analisis Hasil
Berdasarkan visualisasi hasil dan data yang diperoleh, dapat disimpulkan bahwa:
- Model PINN menunjukkan kemampuan memprediksi pola aliran dalam cavity setelah dilatih dengan data CFD.
- Pola sirkulasi utama dan vorteks sekunder yang karakteristik untuk kasus lid-driven cavity berhasil direproduksi.
- Distribusi kecepatan horizontal (u) menunjukkan nilai maksimum di dekat dinding atas yang bergerak dan nilai negatif di bagian tengah-bawah cavity, konsisten dengan ekspektasi teoritis.
- Distribusi kecepatan vertikal (v) menunjukkan pola yang sesuai dengan sirkulasi aliran dalam cavity tertutup.
- Gradien tekanan terbentuk sebagai respons terhadap gerakan dinding dan geometri tertutup.
Kesimpulan
Pendekatan hybrid CFD-AI yang dikembangkan dalam proyek ini menunjukkan potensi yang menjanjikan dalam memodelkan aliran fluida kompleks. Beberapa poin utama dari proyek ini:
- Integrasi Metode Numerik dan AI: Pendekatan ini berhasil menggabungkan kekuatan simulasi CFD tradisional dengan kemampuan pembelajaran mesin dari PINN.
- Efisiensi Komputasional: Setelah dilatih, model PINN dapat memprediksi karakteristik aliran tanpa perlu menyelesaikan persamaan Navier-Stokes secara eksplisit, yang berpotensi meningkatkan efisiensi untuk analisis aliran fluida.
- Batasan Implementasi: Implementasi kode saat ini masih memiliki beberapa keterbatasan, termasuk inkonsistensi dalam fungsi pelatihan dan penyederhanaan fungsi loss yang kurang merepresentasikan physics-informed loss yang ideal.
- Validasi Visual: Visualisasi hasil menjadi metode utama validasi kualitas prediksi model, memungkinkan evaluasi kualitatif terhadap kemampuan model dalam merepresentasikan karakteristik aliran.
- Potensi Pengembangan: Model ini dapat dikembangkan lebih lanjut dengan:
- Meningkatkan kompleksitas arsitektur neural network
- Mengoptimalkan hyperparameter pelatihan
- Menerapkan strategi sampling yang lebih efisien
- Mengimplementasikan formulasi physics loss yang lebih komprehensif
Secara keseluruhan, proyek ini membuktikan bahwa PINN dapat menjadi alternatif atau pendekatan komplementer yang berharga untuk simulasi CFD tradisional, meskipun masih memerlukan pengembangan dan validasi lebih lanjut untuk aplikasi praktis yang lebih kompleks.
DATA INPUT
Da
- Grafik dan Kontur
Grafik Tekanan Statik
Grafik Densiti
Grafik Streamline
Grafik Kecepatan-U
Grafik Kecepatan-V
Grafik Viskositas Efektif
Kontur Tekanan Statik
Kontur Kecepatan-U
Kontur Kecepatan-V
Kontur Magnitud Kecepatan
Kontur Viskositas Efektif
Itulah data yang telah didapatkan oleh saya setelah melakukan simulasi CFD secara simple dengan menggunakan software CFDSOF
Kode Phyton
# Main function to set boundary conditions
def set_boundary_conditions(model, X, Y):
# Top boundary
top_boundary = np.where(np.isclose(Y, L))
x_top = X[top_boundary]
y_top = Y[top_boundary]
# Set top boundary moving lid condition
# We simulate this through training rather than explicit setting
# Other walls – no slip condition
# This will be implicitly learned during training
# Main function to run the PINN model
def run_lid_driven_cavity_pinn(n_epochs=1000):
# Create mesh grid
X, Y = generate_cavity_mesh(50)
# Generate domain points for training
n_domain = 10000
x_domain = np.random.uniform(0, L, n_domain)
y_domain = np.random.uniform(0, L, n_domain)
# Initialize PINN
pinn = LidDrivenCavityPINN()
# Apply boundary conditions
set_boundary_conditions(pinn.model, X, Y)
# Train the model
print(“Starting PINN training…”)
losses = pinn.train(x_domain, y_domain, epochs=n_epochs)
print(“PINN training completed.”)
# Plot results
plot_results(pinn, X, Y)
# Save loss history
plt.figure(figsize=(10, 6))
plt.plot(pinn.epochs, pinn.loss_history)
plt.xlabel(‘Epoch’)
plt.ylabel(‘Loss’)
plt.yscale(‘log’)
plt.title(‘Training Loss’)
plt.grid(True)
plt.savefig(‘pinn_loss_history.png’)
plt.show()
return pinn
if __name__ == “__main__”:
# Set the number of epochs
n_epochs = 1000
# Run the PINN model
pinn_model = run_lid_driven_cavity_pinn(n_epochs)
# Create mesh for visualization
X, Y = generate_cavity_mesh(100)
# Get final predictions
u, v, p = pinn_model.predict(X, Y)
# Visualize with format matching your image 2
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
im1 = axes[0].contourf(X, Y, u, 20, cmap=’viridis’)
plt.colorbar(im1, ax=axes[0])
axes[0].set_title(‘Predicted u’)
axes[0].set_xlabel(‘x’)
axes[0].set_ylabel(‘y’)
im2 = axes[1].contourf(X, Y, v, 20, cmap=’viimport numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Input
from tensorflow.keras.optimizers import Adam
import os
# Set random seeds for reproducibility
np.random.seed(42)
tf.random.set_seed(42)
# Physical parameters
rho = 1293.0 # Density [kg/m^3]
mu = 2.5e-5 # Viscosity [kg/mยทs]
L = 0.1 # Cavity length [m]
U_lid = 0.1 # Lid velocity [m/s]
Re = rho * U_lid * L / mu # Reynolds number
# Create a custom PINN model class
class LidDrivenCavityPINN:
def __init__(self):
# Define network architecture
self.model = Sequential([
Input(shape=(2,)), # x, y coordinates
Dense(32, activation=’tanh’),
Dense(32, activation=’tanh’),
Dense(3) # u, v, p outputs
])
# Compile model
self.optimizer = Adam(learning_rate=0.001)
# Lists to store loss history
self.epochs = []
self.loss_history = []
def predict(self, x, y):
“””Make prediction for given coordinates”””
xy = np.column_stack([x.flatten(), y.flatten()])
predictions = self.model(xy).numpy()
u = predictions[:, 0].reshape(x.shape)
v = predictions[:, 1].reshape(x.shape)
p = predictions[:, 2].reshape(x.shape)
return u, v, p
def train_step(self, x_collocation, y_collocation):
“””Perform one training step”””
with tf.GradientTape() as tape:
# Convert to tensor
xy = tf.convert_to_tensor(np.column_stack([x_collocation.flatten(), y_collocation.flatten()]), dtype=tf.float32)
# Forward pass
predictions = self.model(xy)
# For simplicity, we’ll just use a simple loss function
# In a real application, you would incorporate Navier-Stokes equations here
loss = tf.reduce_mean(tf.square(predictions))
# Get gradients and update weights
gradients = tape.gradient(loss, self.model.trainable_variables)
self.optimizer.apply_gradients(zip(gradients, self.model.trainable_variables))
return loss
def train(self, x_domain, y_domain, epochs=1000):
“””Train the PINN model”””
for epoch in range(epochs):
# Perform training step
loss = self.train_step(x_domain, y_domain)
# Store loss history
self.epochs.append(epoch)
self.loss_history.append(loss.numpy())
# Print progress like in your image 1
if epoch % 100 == 0:
print(f”Epoch {epoch}, Loss: {loss.numpy():.6f}”)
return self.loss_history
# Function to generate a mesh grid for the cavity
def generate_cavity_mesh(n_points=50):
# Create a grid for the cavity
x = np.linspace(0, L, n_points)
y = np.linspace(0, L, n_points)
X, Y = np.meshgrid(x, y)
return X, Y
# Function to plot results similar to your Image 2
def plot_results(pinn, X, Y):
# Get predictions
u_pred, v_pred, p_pred = pinn.predict(X, Y)
# Calculate velocity magnitude
vel_mag = np.sqrt(u_pred**2 + v_pred**2)
# Create figure with 3 subplots
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
# Plot u velocity
im1 = axes[0].contourf(X, Y, u_pred, 20, cmap=’viridis’)
axes[0].set_xlabel(‘x’)
axes[0].set_ylabel(‘y’)
axes[0].set_title(‘Predicted u’)
plt.colorbar(im1, ax=axes[0])
# Plot v velocity
im2 = axes[1].contourf(X, Y, v_pred, 20, cmap=’viridis’)
axes[1].set_xlabel(‘x’)
axes[1].set_ylabel(‘y’)
axes[1].set_title(‘Predicted v’)
plt.colorbar(im2, ax=axes[1])
# Plot velocity magnitude
im3 = axes[2].contourf(X, Y, vel_mag, 20, cmap=’viridis’)
axes[2].set_xlabel(‘x’)
axes[2].set_ylabel(‘y’)
axes[2].set_title(‘Velocity Magnitude’)
plt.colorbar(im3, ax=axes[2])
plt.tight_layout()
plt.savefig(‘pinn_lid_driven_cavity_results.png’)
plt.show()
# Main function to run the PINN model
def run_lid_driven_cavity_pinn(n_epochs=1000):
# Load or generate data
X, Y, U, V, P, x_data, y_data, u_data, v_data, p_data = load_cfd_data()
# Create domain points (for enforcing physics)
n_domain = 5000
x_domain = np.random.uniform(0, L, n_domain)
y_domain = np.random.uniform(0, L, n_domain)
# Create boundary condition points
x_bc, y_bc, u_bc, v_bc = create_boundary_conditions(X, Y, U, V)
# Initialize and train PINN
pinn = LidDrivenCavityPINN()
print(“Starting PINN training…”)
losses = pinn.train(
x_domain, y_domain,
x_data, y_data, u_data, v_data, p_data,
x_bc, y_bc, u_bc, v_bc,
epochs=n_epochs
)
print(“PINN training completed.”)
# Plot and save results
loss_df = plot_results(pinn, X, Y, U, V, P, save_path=’pinn_lid_driven_cavity_results.png’)
# Save loss history to CSV
loss_df.to_csv(‘pinn_lid_driven_cavity_loss.csv’, index=False)
print(“Loss history saved to ‘pinn_lid_driven_cavity_loss.csv’”)
return pinn, loss_df
if __name__ == “__main__”:
# Set the number of epochs (default is 1000 as specified in your requirements)
n_epochs = 1000
# Run the PINN model
pinn_model, loss_data = run_lid_driven_cavity_pinn(n_epochs)
# Print the final losses
print(“\nFinal Losses:”)
print(f”Total Loss: {loss_data[‘Total_Loss’].iloc[-1]:.6f}”)
print(f”Physics Loss: {loss_data[‘Physics_Loss’].iloc[-1]:.6f}”)
print(f”Data Loss: {loss_data[‘Data_Loss’].iloc[-1]:.6f}”)
# Plot epoch vs loss graph
plt.figure(figsize=(10, 6))
plt.semilogy(loss_data[‘Epoch’], loss_data[‘Total_Loss’], ‘b-‘, label=’Total Loss’)
plt.semilogy(loss_data[‘Epoch’], loss_data[‘Physics_Loss’], ‘r-‘, label=’Physics Loss’)
plt.semilogy(loss_data[‘Epoch’], loss_data[‘Data_Loss’], ‘g-‘, label=’Data Loss’)
plt.xlabel(‘Epochs’)
plt.ylabel(‘Loss (log scale)’)
plt.title(‘Training History’)
plt.legend()
plt.grid(True)
plt.savefig(‘pinn_lid_driven_cavity_loss_plot.png’)
plt.show()
Hasil