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
|
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 |