A Physics-Informed Neural Network (PINN) implemented in Python using PyTorch to solve a 1D steady-state heat conduction problem. I’ll also include a simple GUI using tkinter to input parameters and display the results.


Algorithm for PINN 1D Steady Heat Conduction
- Initialization:
- Define a neural network NN(x;ฮธ) with input x and trainable parameters ฮธ
- Set boundary conditions: T(x=0) = T0 โ, T(x=1)=T1โ.
- Choose hyperparameters: learning rate (e.g., 0.001), number of epochs (e.g., 1000), number of collocation points (e.g., 100).
- Discretize Domain:
- Generate N collocation points xi in the domain [0,1] [0, 1] [0,1] (e.g., using torch.linspace).
- Training Loop (for each epoch):
- Step 3.1: Forward pass
- Compute predicted temperature T(xi)=NN(xi;ฮธ) for all xi
- Step 3.2: Compute derivatives
- Calculate dTdxโ using automatic differentiation.
- Calculate d2Tdx2โ by differentiating dTdxโ.
- Step 3.1: Forward pass

import torch
import torch.nn as nn
import numpy as np
import matplotlib.pyplot as plt
import tkinter as tk
from tkinter import ttk
Define the PINN neural network
class PINN(nn.Module):
def init(self):
super(PINN, self).init()
self.net = nn.Sequential(
nn.Linear(1, 20),
nn.Tanh(),
nn.Linear(20, 20),
nn.Tanh(),
nn.Linear(20, 1)
)
def forward(self, x):
return self.net(x)
Function to compute the loss
def compute_loss(model, x, T0, T1):
x = x.requires_grad_(True)
T = model(x)
# Compute derivatives
dT_dx = torch.autograd.grad(T, x, grad_outputs=torch.ones_like(T), create_graph=True)[0]
d2T_dx2 = torch.autograd.grad(dT_dx, x, grad_outputs=torch.ones_like(dT_dx), create_graph=True)[0]
# Physics loss (d^2T/dx^2 = 0)
physics_loss = torch.mean(d2T_dx2**2)
# Boundary conditions
T_left = model(torch.tensor([[0.0]]))
T_right = model(torch.tensor([[1.0]]))
bc_loss = (T_left - T0)**2 + (T_right - T1)**2
return physics_loss + bc_loss
Training function
def train_pinn(T0, T1, epochs=1000):
model = PINN()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
x = torch.linspace(0, 1, 100).reshape(-1, 1)
for epoch in range(epochs):
optimizer.zero_grad()
loss = compute_loss(model, x, T0, T1)
loss.backward()
optimizer.step()
if epoch % 100 == 0:
print(f"Epoch {epoch}, Loss: {loss.item():.6f}")
return model
Function to plot results
def plot_results(model, T0, T1):
x = torch.linspace(0, 1, 100).reshape(-1, 1)
with torch.no_grad():
T_pred = model(x).numpy()
x = x.numpy()
T_analytical = T0 + (T1 – T0) * x
plt.figure(figsize=(8, 6))
plt.plot(x, T_pred, label="PINN Solution")
plt.plot(x, T_analytical, '--', label="Analytical Solution")
plt.xlabel("x")
plt.ylabel("Temperature")
plt.title("1D Steady-State Heat Conduction")
plt.legend()
plt.grid(True)
plt.show()
GUI Application
class PINNApp:
def init(self, root):
self.root = root
self.root.title(“PINN 1D Heat Conduction Solver”)
# Labels and Entries
ttk.Label(root, text="T0 (Left Boundary, ยฐC):").grid(row=0, column=0, padx=5, pady=5)
self.T0_entry = ttk.Entry(root)
self.T0_entry.grid(row=0, column=1, padx=5, pady=5)
self.T0_entry.insert(0, "100")
ttk.Label(root, text="T1 (Right Boundary, ยฐC):").grid(row=1, column=0, padx=5, pady=5)
self.T1_entry = ttk.Entry(root)
self.T1_entry.grid(row=1, column=1, padx=5, pady=5)
self.T1_entry.insert(0, "0")
ttk.Label(root, text="Epochs:").grid(row=2, column=0, padx=5, pady=5)
self.epochs_entry = ttk.Entry(root)
self.epochs_entry.grid(row=2, column=1, padx=5, pady=5)
self.epochs_entry.insert(0, "1000")
# Solve Button
self.solve_button = ttk.Button(root, text="Solve & Plot", command=self.solve)
self.solve_button.grid(row=3, column=0, columnspan=2, pady=10)
def solve(self):
try:
T0 = float(self.T0_entry.get())
T1 = float(self.T1_entry.get())
epochs = int(self.epochs_entry.get())
model = train_pinn(T0, T1, epochs)
plot_results(model, T0, T1)
except ValueError:
tk.messagebox.showerror("Error", "Please enter valid numerical values.")
Run the GUI
if name == “main“:
root = tk.Tk()
app = PINNApp(root)
root.mainloop()