Built on NREL HOPP · Open source

Size and optimize
hybrid microgrids in Python

Py-Microgrid co-optimizes solar PV, wind, battery storage, and gensets against a real load profile. It returns the least-cost system that meets your demand, with full LCOE, net present cost, and CO₂ analysis.

Python 3.10–3.11 BSD-3 licensed PV · Wind · Battery · Genset
4
Technologies co-optimized
PV · wind · battery · genset
3
Economic metrics reported
LCOE · NPC · CO₂
≤20%
Peak-load reduction via
predictive flexible dispatch
Sites per run with
multi-location batching
Capabilities

Everything you need to design a microgrid

From resource data to a fully costed, dispatched system, all in one toolkit.

System optimization

Search component sizes against bounds and let the optimizer return the least-cost configuration that meets your load.

  • Multi-objective sizing
  • PV, wind, battery & genset
  • Bounded search ranges

Predictive battery dispatch

Look-ahead dispatch with optional flexible load shifting that cuts peak demand by up to 20% where the schedule allows.

  • Look-ahead scheduling
  • Flexible-load shifting
  • Grid-charging control

Economic analysis

Every run reports levelized cost of energy, net present cost, and CO₂ emissions over the full project lifetime.

  • LCOE ($/kWh)
  • Net present cost
  • CO₂ emissions

Multi-location batching

Loop over any number of sites, pulling location-specific solar and wind resource data for side-by-side comparison.

  • Batch optimization
  • Per-site resource data
  • Comparative results

HOPP integration

Built directly on NREL's HOPP framework, so simulations use the same validated performance and weather models.

  • NREL resource data
  • Validated weather models
  • Hourly simulation

YAML configuration

Define sites, technologies, and dispatch options in one readable YAML file. Re-run a study without touching code.

  • Single config file
  • Readable & versionable
  • Reproducible runs
Code

A few lines to a costed system

The real package API. Copy, paste, and adapt.

Basic optimization
from py_microgrid.utilities.keys import set_developer_nrel_gov_key
from py_microgrid.simulation.resource_files import ResourceDataManager
from py_microgrid.tools.optimization import SystemOptimizer
from py_microgrid.tools.analysis.bos import EconomicCalculator

# Set your free NREL API key (https://developer.nrel.gov/signup/)
set_developer_nrel_gov_key('your_api_key_here')

# Download solar and wind resource data for the site
resources = ResourceDataManager()
resources.download_solar_data(lat=-33.5265, lon=149.1588)
resources.download_wind_data(lat=-33.5265, lon=149.1588)

# Configure the economic model
economics = EconomicCalculator(discount_rate=0.0588, project_lifetime=25)

# Initialise the optimizer with predictive, flexible-load dispatch
optimizer = SystemOptimizer(
    yaml_file_path='config/site_config.yaml',
    economic_calculator=economics,
    enable_flexible_load=True,
    max_load_reduction_percentage=0.2,
)

# Search ranges per component
bounds = [
    (5000, 50000),   # PV capacity (kW)
    (1, 50),         # Number of wind turbines
    (5000, 30000),   # Battery energy (kWh)
    (1000, 10000),   # Battery power (kW)
    (17000, 30000),  # Genset capacity (kW)
]
initial = [[b[0] + (b[1] - b[0]) * 0.1 for b in bounds]]

# Run the optimization
result = optimizer.optimize_system(bounds, initial)

print(f"LCOE:       ${result['System LCOE ($/kWh)']:.4f}/kWh")
print(f"System NPC: ${result['System NPC ($)']:,.2f}")
print(f"Demand met: {result['Demand Met Percentage']:.2f}%")
Multi-location batch
from py_microgrid.utilities import ConfigManager
from py_microgrid.simulation.resource_files import ResourceDataManager
from py_microgrid.tools.optimization import SystemOptimizer
from py_microgrid.tools.analysis.bos import EconomicCalculator

# Sites to evaluate
sites = [
    {'name': 'Bathurst',    'lat': -33.5265, 'lon': 149.1588},
    {'name': 'Broken Hill', 'lat': -31.9550, 'lon': 141.4540},
    {'name': 'Darwin',      'lat': -12.4634, 'lon': 130.8456},
]

economics = EconomicCalculator(discount_rate=0.0588, project_lifetime=25)
bounds = [(5000, 50000), (1, 50), (5000, 30000), (1000, 10000), (17000, 30000)]
initial = [[b[0] + (b[1] - b[0]) * 0.1 for b in bounds]]

results = {}
for site in sites:
    # Pull resource data for this location
    resources = ResourceDataManager()
    resources.download_solar_data(lat=site['lat'], lon=site['lon'])
    resources.download_wind_data(lat=site['lat'], lon=site['lon'])

    # Point the config at this location
    config = ConfigManager('config/site_config.yaml')
    data = config.load_yaml_safely()
    data['site']['data']['lat'] = site['lat']
    data['site']['data']['lon'] = site['lon']
    config.save_yaml_safely(data)

    optimizer = SystemOptimizer(
        yaml_file_path='config/site_config.yaml',
        economic_calculator=economics,
    )
    results[site['name']] = optimizer.optimize_system(bounds, initial)

# Compare LCOE across sites
for name, r in results.items():
    print(f"{name:12s} LCOE=${r['System LCOE ($/kWh)']:.4f}/kWh  "
          f"demand met={r['Demand Met Percentage']:.1f}%")
site_config.yaml
# site_config.yaml
site:
  data:
    lat: -33.5265          # site latitude
    lon: 149.1588          # site longitude
  solar_resource_file: ""  # auto-filled by ResourceDataManager
  wind_resource_file: ""
  grid_resource_file: ""
  desired_schedule: ""     # hourly load profile, kW

technologies:
  pv:
    system_capacity_kw: 10000
  wind:
    num_turbines: 5
  battery:
    system_capacity_kwh: 10000
    system_capacity_kw: 2000
  grid:
    interconnect_kw: 20000
Get started

Install in three steps

Up and running on Python 3.10 or 3.11 in a few minutes.

1

Install dependencies

pip install HOPP
conda install -c conda-forge glpk coin-or-cbc -y
2

Clone the repository

git clone https://github.com/Hanrong-Huang/Py-Microgrid.git
cd Py-Microgrid
3

Add your NREL API key

# Get a free key: https://developer.nrel.gov/signup/
# Then in Python:
#   from py_microgrid.utilities.keys import set_developer_nrel_gov_key
#   set_developer_nrel_gov_key('your_api_key_here')