Repository navigation
Releases: justinfmccarty/pyepwmorph
Releases · justinfmccarty/pyepwmorph
Release list
v3.6.0
v3.5.0
Radiation morphs change: diffuse horizontal and direct normal now keep the
EPW's own split, and EPWs without extraterrestrial radiation morph correctly.
Global horizontal radiation and every other variable are unchanged.
Fixed
- No direct normal from EPWs with empty extraterrestrial columns. The
radiation morph readexthorrad_Whm2for the clearness index and capped
direct normal atextdirrad_Whm2. weather-file-builder up to 2.3.0 wrote
both as 0 in ERA5 typical and extreme years, so every Radiation or Clouds
and Radiation morph of such a file came out diffuse only, with direct
normal 0 in every hour. When a column holds no positive value it is now
computed from the solar position (newprocedures.extraterrestrial_or_computed,
solar.extraterrestrial_radiation) and a warning is logged. The computed
columns are also written to the morphed EPW (rounded, 0 at night) and named
in COMMENTS 2. Filled columns are used and written as they are.calc_dirnoralso falls back to the solar constant
when its ceiling column is empty.
Changed
- Diffuse and direct normal keep the EPW's split (
procedures.morph_radiation_split).
Before, both were recalculated from scratch with the Ridley et al. (2010)
model, which differs from the model the EPW was split with (weather-file-builder
uses DIRINT). That moved diffuse and direct normal by about 5% even with no
climate signal (an ERA5 TMY at Zurich: diffuse -5%, direct normal +5%), and
the error went into every future file. Now the diffuse fraction is the EPW's
own plus the change the Ridley model predicts between present and morphed
global radiation, bounded so it never passes the model's future value, and
direct normal scales the EPW's own value by the change in horizontal beam
(beam change projected mid-hour where the present beam is under 10 W/m2).
With no climate signal both are now returned unchanged, and the identity
tests require it. Zurich ERA5 TMY, CH2025 GWL 3.0 median (global +2.0%):
diffuse -1.3%, direct normal +4.3% (3.4.0 with the columns filled: -7.7%
and +10.4%). - Radiation solar geometry is taken mid-hour. EPW rows are hour-ending
and the dataframe index marks the start of each hour; the radiation
procedures took the sun's position at that start, 30 minutes early. They
now use the middle (solar_geometry(..., offset_minutes=HOUR_MIDPOINT_MINUTES)).
The returned index and the EPW's date and time columns are unchanged. calc_difhorandcalc_dirnorremain for a full re-split but the morph no
longer calls them.
v3.4.0
v3.3.0
v3.2.0
v3.1.0
v3.0.0
This release corrects several morphing calculations. Morphed humidity, dew
point, wind speed, cloud cover, and direct and diffuse radiation all change,
so files produced by earlier versions should be regenerated. Dry bulb
temperature, pressure, and global horizontal radiation are unaffected.
Fixed
- Relative humidity was inflated even with no climate signal.
morph_relhum
evaluated the psychrometer equation at the dry bulb temperature instead of the
wet bulb temperature, which overstated vapour pressure. Morphing an EPW with an
unchanged specific humidity raised relative humidity by a median of 21% and
pushed hundreds of hours to saturation. The conversion now goes through the
humidity ratio directly and round-trips exactly. - The humidity climate signal was almost entirely discarded.
utilities.relative_deltareturns a ratio, butmorph_relhumtreated it as a
percentage twice over, turning a 20% change in specific humidity into 1%. A
+20% and a -20% projection produced identical output. The full ratio is now
applied. - The wind climate signal was almost entirely discarded.
morph_wspdhad the
same ratio-as-percentage bug: a 20% modelled increase in wind speed morphed to
1.2%. - Direct normal irradiance could reach physically impossible values.
calc_dirnordivided the horizontal beam component by the sine of the solar
altitude with no lower bound, producing values up to 62,000 W/m2 near the
horizon. Hours below a 2 degree solar altitude are now zeroed and the result is
capped at the extraterrestrial direct normal irradiance recorded in the EPW. - Cloud cover changes below 10 percentage points vanished.
calc_tsc
truncated the shift to an integer before applying it, so a 9 percentage point
change in cloud fraction became zero tenths. The shift is now carried as a float
and rounded once, at the end. - Diffuse horizontal irradiance is bounded. The Ridley diffuse fraction is
clipped to [0, 1] and the result can no longer exceed global horizontal. morph_relhumnow returns aDatetimeIndexlike every other procedure, instead
of aRangeIndex.- Appending to the
COMMENTS 2header no longer raises on EPW files that do not
carry that line; it is created beforeDATA PERIODSwhen missing. - The CMIP6 cache key now includes the
time_slicesargument, so a custom
temporal slice no longer silently returns data cut to the default bounds. utilities.ts_8760respects theyearargument when a timezone is supplied; it
previously hard-coded 2022.access.build_accessible_data_listreturnedNone; it now returns the list of
source IDs.
Changed
- Dependencies of a requested variable are now written to the output file.
Previously, asking forHumidityalone computed a morphed dry bulb temperature
internally but discarded it, while asking forDew Pointalone wrote it. Every
resolved dependency is now written, which keeps the morphed EPW internally
consistent.MorphConfig.resolved_variablesexposes the full ordered list. - Solar geometry uses a fixed UTC offset taken from the EPW
LOCATIONline
and the year of the EPW data. It previously looked up a named IANA timezone,
which injected daylight saving shifts into local solar time that the weather
data does not contain, and hard-coded three different years. procedures.calc_dirnorsignature changed. The unusedpresent_dirnor
argument was removed andextraterrestrial_dirnorandmin_solar_altitude
were added:
calc_dirnor(morphed_glohor, morphed_difhor, longitude, latitude, utc_offset, extraterrestrial_dirnor=None, min_solar_altitude=2.0)procedures.calc_oscreturns integer tenths, matchingcalc_tscand the EPW
field definition, instead of floats.- The CMIP6 cache moved from the system temp directory to the per-user cache
directory, so it survives a reboot and is not world-readable on shared hosts.
The default cap rose from 50 MB to 500 MB.PYEPWMORPH_CACHE_DIRand
PYEPWMORPH_CACHE_MAX_MBoverride both. - Cache lookups moved from
coordinate.coordinate_cmip6_datainto
workflow.compile_climate_model_data, so a cache hit no longer opens the
remote catalogue first. Callingcoordinate_cmip6_datadirectly always
recomputes. cache.CACHE_DIRandcache.CACHE_MAX_SIZE_MBwere replaced by
cache.get_cache_dir()andcache.get_cache_max_size_mb(), which read the
environment on each call.- The morphing procedures are vectorised. The per-row
DataFrame.applycalls
were replaced with numpy broadcasting, which cuts the radiation chain from
roughly 1.1 s to a few milliseconds per morph. - Library modules no longer call
warnings.filterwarnings("ignore")at import
time, which used to silence warnings for the whole host process. - The cache and utility modules log instead of printing.
- Minimum pandas raised to 2.2, which is the real floor for the
"ME"and
"h"resample aliases already in use.
Removed
pyepwmorph.tools.ladybug_psychrometrics, which was copied from an
AGPL-3.0 project into an MIT-licensed package. It is replaced by
pyepwmorph.tools.psychrometrics, a vectorised implementation of the same
ASHRAE Handbook (2017) formulas following the MIT-licensed PsychroLib
reference.- Unused dependencies:
meteocalc,skyfield,ipython,lz4,distributed,
andtimezonefinder.
Added
pyepwmorph.tools.psychrometricswith vectorised saturation vapour pressure,
humidity ratio, relative humidity, specific humidity, and dew point functions.configuration.resolve_variable_order, which expands variable dependencies
transitively and returns them in a safe morphing order.Epw.add_comment, which appends toCOMMENTS 2and creates the header in the
correct position when it is absent.utilities.month_factors,utilities.day_factors, andutilities.as_array
for broadcasting monthly and daily climatologies onto an hourly index.solar.fixed_offsetfor building a daylight-saving-free timezone from an EPW
UTC offset.morphing_workflowacceptstime_slicesand forwards it to the CMIP6 fetch.- A continuous integration workflow running ruff and the test suite on Python
3.9 through 3.13. - The test suite grew from 42 to 104 tests, including an identity-morph suite
that asserts an unchanged climate leaves the EPW unchanged for every variable.
That suite alone catches all five numerical bugs fixed in this release.
v2.2.0
What's new
See README for full breaking changes list.
v2.1.1
What's new
See README for full breaking changes list.
v2.1.0
What's new in v2.1.0
See README for full breaking changes list.