Thermal simulation of opaque constructive systems (walls and roofs) from EPW data — 1D and 2D
Project description
EnerHabitat
EnerHabitat is a Python package for the thermal simulation of opaque
constructive systems (walls and roofs) driven by EPW weather data. It solves
the time-dependent heat conduction equation across the system and produces
indoor temperatures and air-conditioning energy demands for an average day
of a chosen month. Homogeneous layer stacks are solved in 1D (System);
units that are heterogeneous across their width, such as concrete
hollow-block walls and joist-and-block (vigueta y bovedilla) roofs, are
solved in 2D over their cross-section (System2D).
📖 Documentation
Full documentation lives at https://ener-habitat.github.io/EnerHabitat/:
- Usage: setup (materials file and configuration), with the executable examples in 1D and 2D, free-running and air-conditioned.
- Theory: 1D model · 2D model · Numerical method (equations, boundary conditions, convergence, validation).
- API reference.
Overview
EnerHabitat models the heat transfer through opaque constructive systems;
windows, ventilation, infiltration and internal heat gains are outside its
scope. Each layer is described by a material name and three properties:
thermal conductivity k (W/(m·K)), density rho (kg/m³) and specific heat
c (J/(kg·K)). The properties come from a user-supplied materials.ini
file; no defaults are bundled.
Given an EPW file and a constructive system, EnerHabitat computes the outdoor
(Ta), sun–air (Tsa), indoor (Ti) and neutrality (Tn) temperatures,
the solar irradiances (Ig GHI, Ib DNI, Id DHI and the plane-of-array
Is) and the energy demands over the average day of the selected month.
Theoretical background (summary)
EnerHabitat solves the time-dependent heat conduction through the constructive system, in 1D across multilayer stacks and in 2D over the cross-section of non-homogeneous units, with flux continuity at the layer joints. The full derivations (equations, boundary conditions, cavity physics, assumptions and numerical method) are in the theory pages.
At the outdoor surface the boundary condition uses the sun–air temperature, which lumps convection, absorbed solar radiation and the long-wave sky exchange:
$$ T_{sa} = T_a + \frac{a, I_s}{h_o} - RF, $$
with a the solar absorptance, $I_s$ the irradiance on the tilted surface
(computed with pvlib) and $RF$ decreasing linearly from 3.9 °C at tilt = 0
(roof) to 0 at tilt = 90 (wall).
At the indoor surface the system exchanges heat with the indoor air, and two
solution modes exist. In the free-running mode (solve()) the indoor air is
a lumped thermal mass whose temperature Ti evolves freely, and the daily
energy delivered to it is reported as energy_transfer. In the
air-conditioned mode (solveAC()) Ti is held at the neutrality temperature
of the adaptive comfort model of Humphreys & Nicol,
$T_n = 0.54,\overline{T_a} + 13.5$ °C, and the required cooling_energy and
heating_energy are reported. The average-day data also includes the
comfort-zone half-width DeltaTn, after Morillón, for comfort analyses.
For 2D systems, System2D solves the same problem on the unit's
cross-section, adding the cavity physics: radiation between the cavity walls
(solved as a radiosity enclosure) and temperature-dependent Nusselt convection
with a lumped cavity-air node.
The equations are discretised with implicit finite control volumes and solved with the TDMA; the average day is iterated until the solution is periodic. Full derivations, boundary conditions, convergence criteria and the validation record are in the theory pages.
Installation
pip install enerhabitat
With uv:
uv add enerhabitat
EnerHabitat requires Python ≥ 3.10. The section inspector plots are an
optional extra: pip install enerhabitat[viz].
Quickstart
EnerHabitat bundles no materials. Create a materials.ini in your working
directory (or point eh.config.file to one) before running anything. A
minimal file for this example:
[Adobe]
k = 0.58 # W/(m·K)
rho = 1500 # kg/m³
c = 1480 # J/(kg·K)
import enerhabitat as eh
# 1) Materials file (required — no defaults are bundled)
eh.config.file = "./materials.ini"
# 2) Location from an EPW file
loc = eh.Location("./epw/example.epw")
# 3) Define the constructive system
wall = eh.System(location=loc)
wall.azimuth = 90 # east-facing
wall.absortance = 0.3
wall.layers = [("Adobe", 0.20)] # outside → inside
# 4) Average day and solar inputs
loc.meanDay(month=5, year=2025)
wall.Tsa()
# 5) Solve (free-running); Tsa() and solve() share the same time grid,
# so results concatenate directly.
ti = wall.solve()
print(wall.energy_transfer) # J/(m²·day)
For a wall with air conditioning, call wall.solveAC() and read
wall.cooling_energy / wall.heating_energy.
2D systems
System2D is used like System (see the
API page for
the differences). Its layers list contains exactly one 2D element: a
HollowBlock (walls, tilt = 90) or a Slab (joist-and-block roofs,
tilt = 0). The materials named below (Concreto, Mortero, Yeso) must
also be defined in your materials.ini (see the
full example set):
block = eh.HollowBlock(
material = "Concreto",
emissivity = 0.9,
geometry = {"web": 0.02, "block_width": 0.16, # optional: "joint_web" (defaults to web)
"cover_top": 0.02, "cavity": 0.08, "cover_bottom": 0.02},
)
wall = eh.System2D(eh.Location("./epw/example.epw"))
wall.tilt = 90
wall.azimuth = 90
wall.absortance = 0.6
wall.layers = [("Mortero", 0.02), block, ("Yeso", 0.01)]
wall.location.meanDay(month=5, year=2025)
wall.Tsa()
ti = wall.solve()
⏱ A 2D solve at the default mesh (80×160) takes ~10–20 minutes; the 1D ones take seconds. For a quick smoke test, reduce the mesh first (e.g.
eh.config2d.nx, eh.config2d.ny = 24, 60) and checkwall.converged.
All the examples (the full 1D/2D × free-running/AC matrix, the joist-and-block roof, and the to-scale section inspector) are in the Usage — 1D and Usage — 2D pages.
API at a glance
| Object | Purpose | Key methods / attributes |
|---|---|---|
Location |
Reads an EPW file, builds the average day | meanDay(month, year) |
System |
1D multilayer wall/roof | layers, Tsa(), solve(), solveAC(), Tso, Tsi, energy_transfer, cooling_energy, heating_energy, days, converged |
System2D |
2D heterogeneous wall/roof | mirror of System (see the API page for the differences), plus preview(), section_report(), Thueco, Tfield |
HollowBlock / Slab |
The 2D element inside System2D.layers |
material(s), fill_type (Fill.AIR/Fill.SOLID), geometry |
config |
Global parameters | file, La, Nx, ho, hi, hi_up, hi_down, hi_flow, dt (fixed) |
config2d |
2D mesh & convergence | nx, ny, tol_inner, tol_day, max_days, max_inner |
The film coefficients are the NOM-008/020-ENER values: ho = 13 and, for
walls, hi = 8.1 W/(m²·K); roofs switch every time step between
hi_up = 9.4 (upward heat flow) and hi_down = 6.6 (downward). Set
hi_flow = False to force the fixed hi everywhere. dt is fixed at 10 s
(see
why).
Full reference:
API page.
Dependencies
Direct dependencies: numba and
pvlib (numpy, pandas and pytz come
with them). Optional: matplotlib via enerhabitat[viz].
How to cite
If you use EnerHabitat in academic work, please cite the reference paper:
Barrios, G., Casas, J.M., Huelsz, G., Rojas, J. (2016). Ener-Habitat: An online numerical tool to evaluate the thermal performance of homogeneous and non-homogeneous envelope walls/roofs. Solar Energy 131, 296–304. https://doi.org/10.1016/j.solener.2015.12.017
@article{Barrios2016,
author = {Barrios, G. and Casas, J.M. and Huelsz, G. and Rojas, J.},
title = {Ener-Habitat: An online numerical tool to evaluate the thermal
performance of homogeneous and non-homogeneous envelope walls/roofs},
journal = {Solar Energy},
volume = {131},
pages = {296--304},
year = {2016},
doi = {10.1016/j.solener.2015.12.017}
}
The repository also ships a CITATION.cff
(GitHub's Cite this repository button) covering the software itself.
Authors of the package
Developed at the Instituto de Energías Renovables, UNAM.
- Guillermo Barrios del Valle, gbv@ier.unam.mx
- Fernando Rodríguez Calderón, ferrodriguez2509@gmail.com
Source code: https://github.com/Ener-Habitat/EnerHabitat · Issues: https://github.com/Ener-Habitat/EnerHabitat/issues
License
Released under the MIT License.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file enerhabitat-0.4.2.tar.gz.
File metadata
- Download URL: enerhabitat-0.4.2.tar.gz
- Upload date:
- Size: 14.9 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9d3aff1ce5d4e1157120530be61980595c98eaaedb5203644b50794cb7cff233
|
|
| MD5 |
a9113010287c11597352d01deb041ebd
|
|
| BLAKE2b-256 |
479f95728ca462e7b1c1f76c905c49102a428ef2e7966f18a36fd9b53472e591
|
File details
Details for the file enerhabitat-0.4.2-py3-none-any.whl.
File metadata
- Download URL: enerhabitat-0.4.2-py3-none-any.whl
- Upload date:
- Size: 57.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5954d099fe82735222864562d15054aa93a213c06e8dfb73e7a018f52427a14a
|
|
| MD5 |
ac257b3596b2ac2adfcb966c39fd4cb4
|
|
| BLAKE2b-256 |
f68dd983348ea64fded1c34e6d4dadb94976785a1c8577c5707edc385c8faee0
|