Weather Class

The weather class allows for editing and saving of the epw file with full access to all parts of the epw file. Users can - Modify an epw manually and parametrically, and save in file system - Modify an epw, and run through besos with run_building() - Parametrically modify an epw, and run through the evaluator for surrogate modelling

First import packages

from besos.weather import *
import besos.eplus_funcs as ep
import besos.eppy_funcs as ef
from besos.parameters import *
from besos.evaluator import EvaluatorEP
from besos.problem import EPProblem
from besos import sampling
from dask.distributed import Client
import time
from inspect import signature

Weather Class Introduction

The weather class takes an epw path as an argument

weather_obj = weather('victoria.epw')

With this object its options can be viewed with .keys

weather_obj.keys
['location',
 'design_conditions',
 'typical_extreme_periods',
 'ground_temperatures',
 'holidays_daylight_savings',
 'comments1',
 'comments2',
 'data_period_header',
 'weather_data']

Each key contains different information

  • location: Editable location dataframe
  • design_conditions: String containing design conditions
  • typical_extreme_periods: String containing typical extreme periods
  • holidays_daylight_savings: String containing holidays daylight savings details
  • comments1: Comments about the weather file
  • comments2: Comments about the weather file
  • data_period_header: Header prior to weather_data, usually contains data periods
  • weather_data: Dataframe containing all the weather data from the epw
weather_obj.location
City Province Country WMO Field1 WMO Field2 Latitude Longitude Timezone Elevation
0 Victoria Int'l BC CAN WYEC2-B-24297 717990 48.65 -123.43 -8.0 19.0
weather_obj.data_period_header
'DATA PERIODS,1,1,Data,Sunday, 1/ 1,12/31'
weather_obj.weather_data.head()
Year Month Day Hour Minute Data Source and Uncertainty Flags Dry Bulb Temperature Dew Point Temperature Relative Humidity Atmospheric Station Pressure ... Ceiling Height Present Weather Observation Present Weather Codes Precipitable Water Aerosol Optical Depth Snow Depth Days Since Last Snowfall Albedo Liquid Precipitation Depth Liquid Precipitation Quantity
0 1970 1 1 1 60 A_A__*A_9*M_Q_M_Q_Q_Q_9_____________*_*___* 0.1 -0.6 94 101810 ... 77770 0 999999999 0 0.0000 0 88 0.000 0.0 0.0
1 1970 1 1 2 60 A_A__*A_9*M_Q_M_Q_Q_Q_9_____________*_*___* 0.5 0.0 96 102500 ... 77770 0 999999999 0 0.0000 0 88 0.000 0.0 0.0
2 1970 1 1 3 60 A_A__*A_9*M_Q_M_Q_Q_Q_9_____________*_*___* 0.8 0.5 98 102970 ... 77770 0 999999999 0 0.0000 0 88 0.000 0.0 0.0
3 1970 1 1 4 60 A_A__*A_9*M_Q_M_Q_Q_Q_9_____________*_*___* 0.8 0.7 99 103190 ... 77770 0 999999999 0 0.0000 0 88 0.000 0.0 0.0
4 1970 1 1 5 60 A_A__*A_9*M_Q_M_Q_Q_Q_9_____________*_*___* 0.8 0.8 100 103270 ... 77770 0 999999999 0 0.0000 0 88 0.000 0.0 0.0

5 rows × 35 columns

The class has multiple functions to use aswell.

  • get_rows(time_params): Returns row indexes that meet the time parameters passed in
  • get_col_bounds(cols, time_params=None): Returns a dataframe with minimum and maximum values of columns provided
  • help(): Returns a dictionary with information of each column in weather_data
  • save_epw(output_path): Saves epw object as output_path with correct formatting

get_rows is useful when iterating over rows for specific information.

Scale the Dry Bulb Temperature by 1.5 for all times in February where the Dew Point Temperature is between 4.1 and 4.5

time_params = {'Month': '2', 'Dew Point Temperature': RangeDescriptor(min_val=4.1,max_val=4.5)}
for row_index in weather_obj.get_rows(time_params):
    weather_obj.weather_data['Dry Bulb Temperature'][row_index] = round(float(weather_obj.weather_data['Dry Bulb Temperature'][row_index])*1.5, 1)
    print(
        'Dry Bulb:',weather_obj.weather_data['Dry Bulb Temperature'][row_index],
        '-- Dew Point:',weather_obj.weather_data['Dew Point Temperature'][row_index],
        '-- Month:',weather_obj.weather_data['Month'][row_index]
    )
Dry Bulb: 10.5 -- Dew Point: 4.3 -- Month: 2
Dry Bulb: 7.5 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 12.5 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 12.5 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 9.1 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 10.8 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 13.4 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 13.4 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 10.1 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 8.4 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 14.1 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 8.4 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 8.4 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 8.4 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 9.1 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 8.4 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 8.4 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 8.4 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 10.1 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 11.7 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 10.1 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 8.4 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 10.1 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 9.1 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 8.4 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 10.1 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 10.8 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 10.1 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 11.7 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 15.0 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 10.1 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 9.1 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 10.1 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 10.1 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 10.1 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 9.1 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 10.1 -- Dew Point: 4.4 -- Month: 2
Dry Bulb: 9.1 -- Dew Point: 4.4 -- Month: 2

To view the maximum and minimums of those same time parameters, use get_col_bounds()

weather_obj.get_col_bounds('Dry Bulb Temperature',time_params=time_params)
Column Minimum Maximum
0 Dry Bulb Temperature 7.5 15.0

Once the wanted changes are made, the epw object can be saved using save_epw()

weather_obj.save_epw('victoria_edited.epw')

Using weather objects in run_building

  • First modify the weather data
  • Run building like regular, with epw argument set to the weather object
building = ef.get_building(mode='idf')
weather_obj = weather('victoria.epw')

First define a custom function to scale and shift the Dry Bulb Temperature by

def eval_func(df_val,values):
    return 1.1*df_val+values

WeatherSelectors have one positional argument, with two optional arguments.

  • col_name: Positional argument defining which column to edit
  • func: Optional argument. Either ‘add’, ‘multiply’ or a custom function to apply to each value. If None, the set function will expect a list values to replace the dataframe with.
  • time_params: Dictionary containing parameters that have to be met to edit values (ex. {‘Month’: ‘2’, ‘Dew Point Temperature’: RangeDescriptor(min_val=4.1,max_val=4.3), ‘Year’: [‘2002’,‘2003’]}
time_params = {'Month':['1','2']}

selectors = [
    WeatherSelector('Dry Bulb Temperature',func=eval_func),
    WeatherSelector('Dew Point Temperature',func='multiply', time_params=time_params),
]

bulb_original = weather_obj.weather_data['Dry Bulb Temperature'].tolist()[0]
dew_original = weather_obj.weather_data['Dew Point Temperature'].tolist()[0]

selectors[0].set(weather_obj,1) # 1 will be the value in eval_func
selectors[1].set(weather_obj,1.2) # each value that meets time_params will be multiplied by 1.2

bulb_after = weather_obj.weather_data['Dry Bulb Temperature'].tolist()[0]
dew_after = weather_obj.weather_data['Dew Point Temperature'].tolist()[0]

print('Dry Bulb Temperature Index 0:',bulb_original,'-->', bulb_after)
print('Dew Point Temperature Index 0:',dew_original,'-->', dew_after)
Dry Bulb Temperature Index 0: 0.1 --> 1.11
Dew Point Temperature Index 0: -0.6 --> -0.72

After editing the epw file, we can then run the building with run_building

results = ep.run_building(building,epw = weather_obj)

Setup for surrogate modelling

  • Import the building
  • setup parameters using WeatherParameter. It can also accept parameters to modify the building at the same time.
  • Add objectives
  • Create the problem
building = ef.get_building(mode='idf')
parameters = [
    WeatherParameter(
        WeatherSelector('Dry Bulb Temperature',func='add'),
        value_descriptors=RangeDescriptor(0,15),
        name='Dry Bulb Temperature',
    ),
    WeatherParameter(
        WeatherSelector('Dew Point Temperature',func='multiply'),
        value_descriptors=CategoryDescriptor(options=[1.1,1.3,1.5,1.2]),
        name='Dew Point Temperature',
    ),
]


# Construct the objective
objective = ['Electricity:Facility']


# Build the problem
problem = EPProblem(parameters, objective)

Create the evaluator

Functionality exists to pass in a weather object into epw or a path to an epw which will be converted into a weather object

evaluator = EvaluatorEP(
    problem,
    building,
    epw='victoria.epw', # in this case, it creates the weather object in the evaluator.
    progress_bar=True,
    out_dir="outputdirectory",
)

Create the sampling inputs dataframe

runs = 5
inputs = sampling.dist_sampler(sampling.lhs, problem, runs)


# sample of the inputs
inputs.head()
Dry Bulb Temperature Dew Point Temperature
0 10.136936 1.1
1 2.991047 1.2
2 5.534683 1.5
3 13.083481 1.3
4 6.553076 1.5
# Setup the parallel processing in the notebook.
client = Client(threads_per_worker=1)
client

Client

Cluster

  • Workers: 4
  • Cores: 4
  • Memory: 17.18 GB

Run simulations and review results

t1 = time.time()
# Run Energyplus
outputs = evaluator.df_apply(inputs, processes = 4)
t2 = time.time()
time_of_sim = t2 - t1
print(round(time_of_sim,0), 'seconds')
/opt/anaconda3/lib/python3.8/site-packages/distributed/worker.py:3376: UserWarning: Large object of size 5.67 MB detected in task graph:
  ("('from_pandas-4bc40f4cb57e09d8b801d026db7ab2b8', ... 1d026db7ab2b8')
Consider scattering large objects ahead of time
with client.scatter to reduce scheduler burden and
keep data on workers

    future = client.submit(func, big_data)    # bad

    big_future = client.scatter(big_data)     # good
    future = client.submit(func, big_future)  # good
  warnings.warn(
50.0 seconds
results = inputs.join(outputs)
results.head()
Dry Bulb Temperature Dew Point Temperature Electricity:Facility
0 10.136936 1.1 1.852986e+09
1 2.991047 1.2 1.852986e+09
2 5.534683 1.5 1.852986e+09
3 13.083481 1.3 1.852986e+09
4 6.553076 1.5 1.852986e+09