Machine learning-inspired energy system optimization

Energy system optimization is a complex, multi-dimensional problem. With the increased focus on renewable energy and cost-effective green technologies, optimizing systems such as hydrogen production has become critical. This blog post explores how machine learning-inspired optimization methods, specifically gradient descent, can help improve energy system operations. We’ll illustrate these concepts using a toy hydrogen production cost model written in Python.

What is Gradient Descent?

Gradient descent is a popular optimization algorithm, commonly used in machine learning to minimize loss functions by iteratively adjusting model parameters. The idea is simple: calculate the gradient of the objective function with respect to its parameters, and take small steps in the direction that reduces the objective function.

In energy system optimization, gradient descent can be applied to minimize costs, emissions, or other desired objectives. For example, in hydrogen production, we might want to optimize system parameters such as the electrolyzer capacity or storage to reduce the levelized cost of hydrogen (LCOH). By applying gradient descent to an energy model, we can efficiently search for the best parameter values.

Toy Hydrogen Production Cost Model

Our toy model simulates a hydrogen production system that includes an electrolyzer and hydrogen storage. The electrolyzer produces hydrogen based on electricity inputs, and the storage system buffers supply and demand variations. The model takes in the following key parameters to optimize:

The goal is to optimize these parameters to minimize the LCOH while meeting all hydrogen demand throughout the year.

Loading Input Data

To get started, we load the electricity price data and hydrogen demand profile, both of which are used to determine the system’s costs.

import pandas as pd
import numpy as np

# Load the electricity price data
grid_price = pd.read_csv('example_power_prices_germany.csv')
grid_price_hourly = grid_price['Price (EUR/MWhe)'].values / 1000  # Convert from EUR/MWh to EUR/kWh

# Create a hydrogen demand profile
h2_demand__kg_per_hour = 50 + 30 * np.sin(np.linspace(0, 2 * np.pi, 8760))  # Seasonal demand pattern

Running the Cost Model

The hydrogen cost model calculates the LCOH based on the input parameters, which include electricity prices, electrolyzer size, and storage capacity.

from hydrogen_cost_model import hydrogen_supply_cost

# Define initial parameters
electrolyzer_size__mw = 10.0
capacity_factors = np.ones(8760) * 0.5  # 50% capacity factor for every hour
storage_capacity__t = 10.0

# Calculate the initial LCOH
lcoh, *_ = hydrogen_supply_cost(h2_demand__kg_per_hour, grid_price_hourly, electrolyzer_size__mw, capacity_factors, storage_capacity__t)
print(f"Unoptimized LCOH: {lcoh:.2f} USD/kg")

Applying Gradient Descent

We can apply gradient descent to iteratively improve the LCOH. Here, we use JAX and Optax, popular machine learning tools, to perform the optimization.

import jax
import jax.numpy as jnp
import optax

# Define the optimizer
def create_optimizer(learning_rate):
    return optax.adam(learning_rate)

# Set initial learning rates
learning_rate = 0.01
optimizer = create_optimizer(learning_rate)

# Define the gradient update function
@jax.jit
def gradient_update(params, opt_state, demand, price):
    lcoh_fn = lambda p: hydrogen_supply_cost(demand, price, *p)[0]
    grads = jax.grad(lcoh_fn)(params)
    updates, opt_state = optimizer.update(grads, opt_state)
    params = optax.apply_updates(params, updates)
    return params, opt_state

# Initialize parameters and optimizer state
params = (electrolyzer_size__mw, capacity_factors, storage_capacity__t)
opt_state = optimizer.init(params)

# Run gradient descent
for i in range(1000):
    params, opt_state = gradient_update(params, opt_state, h2_demand__kg_per_hour, grid_price_hourly)
    if i % 100 == 0:
        lcoh = hydrogen_supply_cost(h2_demand__kg_per_hour, grid_price_hourly, *params)[0]
        print(f"Iteration {i}, LCOH: {lcoh:.2f} USD/kg")

Results and Visualization

After running the optimization, we can observe how the LCOH decreases over the iterations, showing the benefits of applying gradient descent in this context. By plotting the LCOH over iterations, we see a downward trend indicating that the model is becoming more cost-effective.

import matplotlib.pyplot as plt

# Plot LCOH history
plt.plot(lcoh_history)
plt.xlabel('Iteration')
plt.ylabel('LCOH (USD/kg)')
plt.title('Learning Curve: LCOH Optimization')
plt.show()

Conclusion

Using gradient descent to optimize energy systems such as hydrogen production is a powerful approach. By leveraging machine learning tools like JAX and Optax, we can efficiently minimize costs and improve system performance. This method can be extended to other energy applications, making it a versatile tool for researchers and practitioners aiming to enhance renewable energy systems.

Feel free to explore the full code and experiment with different learning rates or optimization techniques to see how they impact the cost of hydrogen production.