Physics-Informed Transient Groundwater Flow (PiTGWFlow)¶
- API Reference:
The PiTGWFlow model is a powerful application of deep learning to
solve a fundamental problem in hydrogeology: the 2D transient
groundwater flow equation. It stands as a prime example of a
Physics-Informed Neural Network (PINN), a class of models that
learn directly from the governing physical laws themselves, rather
than from large, labeled datasets.
Instead of traditional numerical methods like Finite Element or Finite
Difference which require complex mesh generation and solve for values
at discrete points, PiTGWFlow leverages a simple Multi-Layer
Perceptron (MLP) as a universal function approximator. This MLP
learns to represent the hydraulic head, \(h\), as a continuous
and differentiable function of time \(t\) and space
\((x, y)\). The model is trained not by comparing its output to
known data points, but by minimizing the residual of the PDE itself
at thousands of randomly sampled “collocation points” within the
domain. This forces the neural network to discover a solution that is
inherently consistent with the physics of groundwater flow.
Key Features¶
Mesh-Free Differential Equation Solver The model uses a neural network to represent the solution space, completely bypassing the need for complex and computationally expensive mesh generation. This makes it particularly well-suited for problems with irregular or complex domain geometries.
Unsupervised, Physics-Driven Training
PiTGWFlowoperates in a purely unsupervised manner. Its loss function is the Mean Squared Error of the PDE residual. In effect, the “label” it trains against is always zero—the value the PDE residual should have if the equation is perfectly satisfied. This eliminates the need for large, labeled datasets, making it ideal for data-scarce scientific applications.Enables Parameter Discovery (Inverse Modeling) One of the most powerful features of the PINN approach is the ability to solve inverse problems. Key physical coefficients like hydraulic conductivity (\(K\)) and specific storage (\(S_s\)) can be declared as trainable variables. The model can then infer the values of these parameters that best satisfy the governing equation, effectively discovering the underlying physics from sparse observations (when integrated into a hybrid loss).
Simple and Familiar API Despite the complex underlying mathematics (automatic differentiation for computing PDE derivatives), the entire training process is encapsulated within the standard, user-friendly Keras workflow. The model is instantiated, compiled with .compile(), and trained with .fit(), making this advanced scientific computing technique highly accessible.
When to Use PiTGWFlow¶
PiTGWFlow is an excellent choice for a range of hydrogeological
problems where the physics of the system are well understood.
Solving the Forward Problem This is the classic use case for a PDE solver. When you know the physical parameters of your aquifer system (\(K\), \(S_s\), \(Q\)) and the boundary/initial conditions, you can use
PiTGWFlowto accurately predict the evolution of the hydraulic head field, \(h(t, x, y)\), over any point in your domain.Solving the Inverse Problem This is a key strength of the PINN methodology. If you have sparse measurements of the hydraulic head at a few locations,
PiTGWFlowcan be used as the core of a system to infer the unknown physical parameters of the aquifer. By setting parameters like K to be learnable, the model can find the values that cause the PDE solution to best fit the sparse observations.For Problems Governed by Known Physics with Scarce Data The model shines in scenarios where you trust the governing equation more than you trust the availability or quality of your data. It provides a way to generate a high-fidelity, continuous solution field from the physical laws themselves, which can then be used for further analysis.
To Obtain a Continuous and Differentiable Solution Unlike traditional numerical solvers that produce values at discrete grid points, the
PiTGWFlowmodel learns a continuous analytical function. This is a significant advantage, as it means you can:Evaluate the solution \(h\) at any continuous coordinate \((t, x, y)\).
Analytically compute its derivatives using
tf.GradientTapeto find other physical quantities, such as the groundwater flow velocity field (\(\mathbf{v} = -K \nabla h\)), without introducing numerical discretization errors.
The Governing Equation¶
The PiTGWFlow model is designed to solve one of the most fundamental
equations in hydrogeology: the 2D transient groundwater flow
equation. This equation is derived from Darcy’s Law and the principle
of conservation of mass, and it describes how the hydraulic head (a
measure of groundwater level) changes in time and space within an
aquifer.
The equation is expressed as:
This can be written more compactly using the Laplacian operator, \(\nabla^2 h = \frac{\partial^2 h}{\partial x^2} + \frac{\partial^2 h}{\partial y^2}\), which represents the net divergence of flow at a point. The equation balances the change in storage against subsurface flow and external sources/sinks:
Let’s break down each term:
\(h(t, x, y)\): The hydraulic head, which is the unknown function that the neural network learns to approximate. It represents the potential energy of the groundwater at a given point and time.
\(\frac{\partial h}{\partial t}\) (The Transient Term): This is the rate of change of the hydraulic head over time. It quantifies how quickly water levels are rising or falling. A positive value means the water level is increasing, and vice-versa.
\(\nabla^2 h\) (The Laplacian Term): This term describes the net “curvature” of the hydraulic head surface in space. A non-zero Laplacian indicates an imbalance of flow. For instance, at the center of a pumping well’s cone of depression, the Laplacian is large and negative, indicating that water is flowing into that point from all directions faster than it is flowing out.
\(S_s\) (Specific Storage): A crucial physical property of the aquifer. It represents the volume of water that a unit volume of the aquifer releases from storage for every unit decline in hydraulic head, due to the compressibility of both the water and the aquifer’s porous skeleton.
\(K\) (Hydraulic Conductivity): A parameter that measures how easily water can move through the soil or rock. High-permeability materials like sand have a high \(K\), while low-permeability materials like clay have a very low \(K\).
\(Q\) (Source/Sink Term): This term accounts for any water being artificially added to (e.g., via injection wells) or removed from (e.g., via pumping wells) the aquifer system per unit volume.
Architectural Workflow: A Deep Dive¶
The PiTGWFlow architecture is elegant in its simplicity. It combines
a standard neural network with a custom, physics-driven training loop that
enforces the governing equation described above.
1. The Neural Network Surrogate¶
The core of the model is a simple Multi-Layer Perceptron (MLP). In the context of PINNs, this MLP acts as a universal function approximator. Its job is to learn a continuous function, \(h_{NN}(\theta; t, x, y)\), that serves as a surrogate for the true, unknown solution \(h\).
The inputs to this network are only the continuous spatio-temporal coordinates, and its output is a single scalar value—the predicted hydraulic head at that point.
Here, \(\theta\) represents all the trainable weights and biases of the MLP.
2. The Physics-Informed Training Step¶
This is where the “physics” is injected. Instead of comparing the
network’s output to ground-truth labels, the training process forces
the network’s output to obey the PDE. This happens in several stages
within the custom train_step:
A. Collocation Point Sampling: For each training step, the model receives a batch of random spatio-temporal points, \((t, x, y)\), called collocation points. These points are sampled from within the problem’s domain and are where the physical law will be evaluated and enforced.
B. Forward Pass: The coordinates of these collocation points are fed through the MLP surrogate to get the predicted head values, \(h_{NN}\), at each of those points.
C. Automatic Differentiation: This is the core mechanism of PINNs. The model uses TensorFlow’s
GradientTape, a powerful tool that acts like a “computational microscope,” to calculate the exact partial derivatives of the MLP’s output (\(h_{NN}\)) with respect to its inputs (\(t, x, y\)). It computes all terms needed for the PDE:\[\frac{\partial h_{NN}}{\partial t}, \quad \frac{\partial h_{NN}}{\partial x}, \quad \frac{\partial h_{NN}}{\partial y}, \quad \frac{\partial^2 h_{NN}}{\partial x^2}, \quad \frac{\partial^2 h_{NN}}{\partial y^2}\]D. Residual Calculation: These analytically computed derivatives are then plugged into the governing groundwater flow equation to calculate the PDE residual, \(R\), for each collocation point. A perfect solution would have \(R=0\) everywhere.
\[R = S_s \frac{\partial h_{NN}}{\partial t} - K \left( \frac{\partial^2 h_{NN}}{\partial x^2} + \frac{\partial^2 h_{NN}}{\partial y^2} \right) - Q\]E. Loss Computation: The model’s loss function, \(\mathcal{L}\), is simply the Mean Squared Error of these residuals. The goal of training is to find the network weights \(\theta\) (and any learnable physical parameters) that make this loss as close to zero as possible.
\[\mathcal{L}(\theta, K, S_s, Q) = \frac{1}{N}\sum_{i=1}^{N} (R_i)^2\]
3. End-to-End Optimization¶
The final step is to compute the gradient of the physics loss \(\mathcal{L}\) with respect to all trainable variables in the model. This includes:
The weights and biases of the MLP surrogate (\(\theta\)).
Any physical parameters that were defined as Learnable (e.g., LearnableK, LearnableSs).
The optimizer (e.g., Adam) then uses these gradients to update all variables, simultaneously tuning the neural network to better approximate the solution field and tuning the physical parameters to values that best describe the system.
Complete Example¶
This example demonstrates a complete workflow for using PiTGWFlow
to solve a forward problem where we also ask the model to perform
parameter discovery for the hydraulic conductivity (\(K\)).
Step 1: Imports and Setup
First, we import the necessary libraries from TensorFlow and
fusionlab-learn, and set up a directory to save our results.
1import os
2import numpy as np
3import tensorflow as tf
4import matplotlib.pyplot as plt
5
6# FusionLab imports
7from fusionlab.nn.pinn import PiTGWFlow
8from fusionlab.params import LearnableK
9
10os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' # Suppress logs
11
12EXERCISE_OUTPUT_DIR = "./pitgwflow_outputs"
13os.makedirs(EXERCISE_OUTPUT_DIR, exist_ok=True)
Step 2: Generate Collocation Points
Unlike traditional models, PINNs are not trained on labeled data. Instead, they learn by minimizing the PDE residual at thousands of randomly sampled points, known as collocation points, within the problem’s spatio-temporal domain.
We also create a dummy_y tensor of zeros. This is required to satisfy
the Keras .fit() API, which expects data in an (X, y) format, but
these dummy targets are completely ignored during training. The actual
loss is derived solely from the physics.
1# Configuration
2N_POINTS = 5000
3BATCH_SIZE = 128
4
5# Generate random (t, x, y) coordinates within a defined domain
6tf.random.set_seed(42)
7coords = {
8 "t": tf.random.uniform((N_POINTS, 1), 0, 10), # Time from 0 to 10
9 "x": tf.random.uniform((N_POINTS, 1), -1, 1), # x from -1 to 1
10 "y": tf.random.uniform((N_POINTS, 1), -1, 1), # y from -1 to 1
11}
12
13# Dummy targets are required for the Keras API but are ignored
14dummy_y = tf.zeros((N_POINTS, 1))
15
16# Create an efficient tf.data.Dataset for training
17dataset = tf.data.Dataset.from_tensor_slices(
18 (coords, dummy_y)
19).shuffle(N_POINTS).batch(BATCH_SIZE).prefetch(tf.data.AUTOTUNE)
20
21print(f"Generated {N_POINTS} collocation points for training.")
Step 3: Define, Compile, and Train PiTGWFlow
We now instantiate the PiTGWFlow model. Note how we pass Ss and Q
as fixed Python floats, but we pass K as a LearnableK object. This
tells the model to treat \(K\) as a trainable parameter to be
discovered during optimization.
Because the model uses its own internal PDE residual loss, we only need
to call .compile() to set up the optimizer.
1# Instantiate PiTGWFlow with a learnable K
2pinn_model = PiTGWFlow(
3 hidden_units=[40, 40, 40],
4 activation='tanh',
5 K=LearnableK(1.0), # The model will infer this value
6 Ss=1e-4, # Fixed value
7 Q=0.0 # Fixed value
8)
9
10# Compile the model (loss is handled internally)
11pinn_model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3))
12
13print("Training PiTGWFlow model...")
14history = pinn_model.fit(
15 dataset,
16 epochs=25, # Use more epochs for a more converged solution
17 verbose=0
18)
19print("Training complete.")
20
21# Extract the final learned value for K
22# The name 'param_K' is set internally by the model
23learned_k = [v for v in pinn_model.trainable_variables if 'param_K' in v.name]
24if learned_k:
25 # The model learns log(K), so we take the exp()
26 final_k_value = tf.exp(learned_k[0]).numpy().mean()
27 print(f"Final Learned K: {final_k_value.mean():.4f}")
Step 4: Visualize Training History
After training, we should always inspect the learning curve. A steadily decreasing pde_loss indicates that the neural network is successfully learning a function that minimizes the PDE residual, thus satisfying the governing physical law.
1from fusionlab.nn.models.utils import plot_history_in
2
3print("\nPlotting training history...")
4plot_history_in(history, metrics={"PDE Loss": ["pde_loss"]})
Expected Output Plot:
An example plot showing the PDE loss decreasing over epochs. The logarithmic scale helps visualize the rapid reduction in error as the model learns to satisfy the physics.¶
Step 5: Visualize the Learned Solution
The key advantage of the PINN is that it has learned a continuous function \(h(t, x, y)\). We can now evaluate this function on a regular grid of points to visualize the full solution field at a specific moment in time.
1# 1. Create a meshgrid for visualization at a specific time slice
2t_slice = 5.0
3x_range = np.linspace(-1, 1, 100)
4y_range = np.linspace(-1, 1, 100)
5X, Y = np.meshgrid(x_range, y_range)
6
7# 2. Prepare grid coordinates for prediction
8x_flat = tf.convert_to_tensor(X.ravel(), dtype=tf.float32)
9y_flat = tf.convert_to_tensor(Y.ravel(), dtype=tf.float32)
10t_flat = tf.fill(x_flat.shape, t_slice)
11
12grid_coords = {
13 't': tf.reshape(t_flat, (-1, 1)),
14 'x': tf.reshape(x_flat, (-1, 1)),
15 'y': tf.reshape(y_flat, (-1, 1))
16}
17
18# 3. Predict the hydraulic head 'h' on the grid
19h_pred_flat = pinn_model.predict(grid_coords)
20h_pred_grid = tf.reshape(h_pred_flat, X.shape)
21
22# 4. Plot the contour of the solution
23plt.figure(figsize=(9, 7))
24contour = plt.contourf(X, Y, h_pred_grid, 100, cmap='jet_r')
25plt.colorbar(contour, label='Hydraulic Head (h)')
26plt.title(f'Learned Hydraulic Head Solution at t = {t_slice}')
27plt.xlabel('x-coordinate')
28plt.ylabel('y-coordinate')
29plt.axis('equal')
30plt.show()
Expected Output Plot:
A 2D contour map showing the continuous hydraulic head field learned by the model. The smooth contours demonstrate the differentiable nature of the neural network solution.¶
Next Steps¶
Note
Now that you understand the theory and the complete workflow for
PiTGWFlow, you can apply these concepts to solve your own forward
or inverse hydrogeological problems.
Proceed to the exercises for more hands-on practice: Exercise: Solving a Forward Problem with PiTGWFlow