Skip to content

script_tutorial

Weili edited this page Jul 26, 2019 · 7 revisions

Script Tutorial

BuildSim Cloud is one of the quickest methods to unlock the potential of the energy modelings with public or commercial design software. In this example, we will start with an energy model from DesignBuilder and then move to BuildSim for parametric analysis.

Before the tutorial, make sure you have the latest BuildSimHub python API downloaded. pip install BuildSimHubAPI We also recommend to have pandas package installed as some of the JSON requests can be easily converted into pandas dataframe, which are much nicer to view and easier to access.

Ok, without further due, let's begin!

DesignBuilder

DesignBuilder (DB) is a whole building energy modeling software that is capable of performing energy, lighting and CFD simulations with one geometry. With its powerful geometry and HVAC editors, creating a full mass model takes less than 10 minutes and here is what I built with DB: DB image and HVAC

This is a two-story courtyard shape office building with 5 zone layout. I also build one VAV with terminal reheat system per floor in the model.

We can safely export this model to EnergyPlus using DB's export function.

Upload

The EnergyPlus exported from DesignBuilder v5.x is still 8.6. However, it is recommended to upgrade the version to 8.7 as the majority of default data templates on BuildSim Cloud are stored as 8.7 and above. You can find the IDFVersionUpgrade in the downloaded EnergyPlus package.

upgrade idf

Once upgraded, we can then upload this model to the platform - simply drop it to the page. drop the model

Once the project is created, you can then find the API keys to the project. Copy the project api key and model api key for the scriptings. APIs

Script!

Now we have both keys, we can start the initial setup for script!

importBuildSimHubAPIasbshapiproject_api_key="1a920abf-ca01-4ead-9dde-dce1c629cd2c"model_api_key="d8aa9a0c-2529-4c6b-b9d2-949e0ebddf71"bsh=bshapi.BuildSimHubAPIClient()

Remember to keep these four lines of script on top of all the script below. Now All set! Let's run our first simulation.

Run simulation

newsj=bsh.new_simulation_job(project_api_key) model=newsj.run_model_simulation(track_token=model_api_key, track=True, unit='si') print(str(model.net_site_eui()) +" "+model.last_parameter_unit)
'''Submitting simulation request...Received server responseLooking for available simulation engine... 1%Initializing Simulation... 17%February... 28%March... 33%May... 44%July... 56%August... 61%October... 72%December... 83%Writing Simulation Results... 89%Collecting Simulation Results... 94%Simulation finished successfullyCompleted! You can retrieve results using the key: 513-7702-783981344.77 kWh/m2'''

View model

After a successful simulation, let's take a look at the model.

model=bsh.model_results(project_api_key, model_api_key)
model.bldg_geo()

This immediately opens the 3D viewer in a broswer. We can view the geometry of the model: geometry and we can also view the HVAC systems that connects to the geometry: hvac

Building data

There are a number of building level data that we can extract from the model using python API library

model=bsh.model_results(project_api_key, model_api_key) print("EUI: "+str(model.net_site_eui()) +" "+model.last_parameter_unit) print("Orientation: "+str(model.bldg_orientation())) print("Floors above ground: "+str(model.num_above_ground_floor())) print("Total floors: "+str(model.num_total_floor())) print("Number of zones: "+str(model.num_zones())) print("Number of conditioned zones: "+str(model.num_condition_zones())) print("Conditioned floor area: "+str(model.condition_floor_area(unit='si')) +" "+model.last_parameter_unit) print("Gross floor area: "+str(model.gross_floor_area(unit='si')) +" "+model.last_parameter_unit) print("Gross Window wall ratio: "+str(model.window_wall_ratio())) print("Cooling unmet hours: "+str(model.not_met_hour_cooling()) +" "+model.last_parameter_unit) print("Heating unmet hours: "+str(model.not_met_hour_heating()) +" "+model.last_parameter_unit) print("Electricity: "+str(model.total_end_use_electricity()) +" "+model.last_parameter_unit) print("Natural Gas: "+str(model.total_end_use_naturalgas()) +" "+model.last_parameter_unit) print("Cooling Electricity: "+str(model.cooling_electricity()) +" "+model.last_parameter_unit) print("Fan Electricity: "+str(model.fan_electricity()) +" "+model.last_parameter_unit) print("Heating Natural Gas: "+str(model.heating_naturalgas()) +" "+model.last_parameter_unit) print("Interior Equipment Electricity: "+str(model.interior_equipment_electricity()) +" "+model.last_parameter_unit) print("Interior Lighting Electricity: "+str(model.interior_lighting_electricity()) +" "+model.last_parameter_unit) print("Pump Electricity: "+str(model.pumps_electricity()) +" "+model.last_parameter_unit) print("Bldg LPD: "+str(model.bldg_lpd()) +" "+model.last_parameter_unit) print("Bldg EPD: "+str(model.bldg_epd()) +" "+model.last_parameter_unit) print("Wall R value: "+str(model.wall_rvalue()) +" "+model.last_parameter_unit) print("Roof R value: "+str(model.roof_rvalue()) +" "+model.last_parameter_unit) print("Window U value: "+str(model.window_uvalue()) +" "+model.last_parameter_unit) print("Window SHGC: "+str(model.window_shgc())) print("Roof solar absorption: "+str(model.roof_absorption())) print("Bldg infiltration: "+str(model.bldg_infiltration()) +" "+model.last_parameter_unit) print("Cooling DX coil COP: "+str(model.bldg_dx_cooling_efficiency())) print("Electric boiler efficiency: "+str(model.bldg_electric_boiler_efficiency())) print("Fuel boiler efficiency: "+str(model.bldg_fuel_boiler_efficiency())) print("Heating DX coil COP: "+str(model.bldg_dx_heating_efficiency()))
'''EUI: 344.77 kWh/m2Orientation: 0.0Floors above ground: 2Total floors: 2Number of zones: 8.0Number of conditioned zones: 8.0Conditioned floor area: 575.957888 m2Gross floor area: 575.957888 m2Gross Window wall ratio: 27.380142745039414Cooling unmet hours: 2.83 HoursHeating unmet hours: 0.0 HoursElectricity: 156467.79 kWhNatural Gas: 42103.67 kWhCooling Electricity: 72525.23 kWhFan Electricity: 31987.92 kWhHeating Natural Gas: 42103.67 kWhInterior Equipment Electricity: 24880.34 kWhInterior Lighting Electricity: 26954.82 kWhPump Electricity: 109.67 kWhBldg LPD: 14.999999999999996 W/m2Bldg EPD: 11.77 W/m2Wall R value: 3.8022813688212924Roof R value: 2.7472527472527473Window U value: 1.96 kWhWindow SHGC: 0.691Roof solar absorption: 0.15000000000000002Bldg infiltration: 0.052 ACHCooling DX coil COP: -1Electric boiler efficiency: -1Fuel boiler efficiency: 0.89Heating DX coil COP: -1'''

Modify the LPD

It seems the LPD of the building is at the high end with 15 W/m2. Let's firstly analyze how the LPD assigned to different zones. To view zone infomations, we can use a little help from pandas to organize data

importpandasaspdmodel=bsh.model_results(project_api_key, model_api_key) zone_df=pd.DataFrame(model.zone_list()) print(zone_df.to_string())
'''This will give us a nicely printed pandas data frame: conditioned floor zone_cool zone_exhaust zone_heat zone_name zone_vent0 Yes 1 Floor1AirLoop Floor1AirLoop Floor1:South Floor1AirLoop1 Yes 1 Floor1AirLoop Floor1AirLoop Floor1:North Floor1AirLoop2 Yes 1 Floor1AirLoop Floor1AirLoop Floor1:West Floor1AirLoop3 Yes 1 Floor1AirLoop Floor1AirLoop Floor1:East Floor1AirLoop4 Yes 2 Floor2AirLoop Floor2AirLoop Floor2:West Floor2AirLoop5 Yes 2 Floor2AirLoop Floor2AirLoop Floor2:South Floor2AirLoop6 Yes 2 Floor2AirLoop Floor2AirLoop Floor2:North Floor2AirLoop7 Yes 2 Floor2AirLoop Floor2AirLoop Floor2:East Floor2AirLoop'''

With the zone list, we can then investigate the LPD assigned to each zone

model=bsh.model_results(project_api_key, model_api_key) zone_df=pd.DataFrame(model.zone_list()) # we will iterate through rows, get the conditioned zone nameforidx, rowinzone_df.iterrows(): ifrow['conditioned'] =='Yes': zone_name=row['zone_name'] info=model.zone_info(zone_name)
#print(info)print(zone_name+": "+str(float(info['zone_lpd']) /float(info['zone_area'])))
'''Floor1:South: 15.0Floor1:North: 14.999999999999998Floor1:West: 15.0Floor1:East: 15.0Floor2:West: 15.0Floor2:South: 15.0Floor2:North: 14.999999999999998Floor2:East: 15.0'''

It seems all the zones have 15W/m2 lighting power density. Let's install LPDs on the first floor first:

model=bsh.model_results(project_api_key, model_api_key) # apply lighting power density# lsit all the zones we want to updatezone_list= ['Floor1:South', 'Floor1:North', 'Floor1:West', 'Floor1:East'] # sets the lights template for the zonesimportBuildSimHubAPI.healpersashplight=hp.EnergyPlusObject("Lights")
light.add_field_template('Design Level Calculation Method','Watts/Area']
light.add_field_template('Watts per Zone Floor Area','6.5']
# apply design updated_model_api=model.add_modify_zone(zone_list, [light]) # get updated modelupdated_model=bsh.model_results(project_api_key, updated_model_api) # compare the differences bsh.compare_models(model, updated_model)

The last line of the script opens the comparison of the two models in your browser: comparison Clearly, we can see the lights in floor 1 zones are all updated according to the template, and all the zone lights on second floor are remain the same. Let's add daylight sensor to all the zones to reduce the LPD further!

model=bsh.model_results(project_api_key, model_api_key) # define design option: daylight sensors daylit_sensor=bshapi.measures.DaylightingSensor() daylit_sensor.set_data(1) updated_model_api=model.apply_measures([daylit_sensor]) updated_model=bsh.model_results(project_api_key, updated_model_api) # compare the differences bsh.compare_models(model, updated_model)

compare daylit By comparing these two models, we see the daylight sensors are successfully added to the model! Let's now run the simulation again and compare the results.

# let reuse the run simulation code and LPD codenewsj=bsh.new_simulation_job(project_api_key) model=newsj.run_model_simulation(track_token=model_api_key, track=True, unit='si') print(str(model.net_site_eui()) +" "+model.last_parameter_unit)
zone_df=pd.DataFrame(model.zone_list()) # we will iterate through rows, get the conditioned zone nameforidx, rowinzone_df.iterrows(): ifrow['conditioned'] =='Yes': zone_name=row['zone_name'] info=model.zone_info(zone_name)
#print(info)print(zone_name+": "+str(float(info['zone_lpd']) /float(info['zone_area'])))
'''......Completed! You can retrieve results using the key: 513-7702-783983282.46 kWh/m2Floor1:South: 6.5Floor1:North: 6.5Floor1:West: 6.500000000000001Floor1:East: 6.5Floor2:West: 15.0Floor2:South: 15.0Floor2:North: 14.999999999999998Floor2:East: 15.0'''

Yes, we successfully reduce the energy consumption from 344.77 kWh/m2 to 282.46 kWh/m2, that is a huge jump! Next, how about reducing the LPD of the second floor zones programmatically?

model=bsh.model_results(project_api_key, model_api_key) lit_df=pd.DataFrame(model.get_class('Lights')) print(lit_df.to_string()) foridx, rowinlit_df.iterrows(): # if there is lights object that has higher than 10 W/m2, we will then update it. iffloat(row['Watts per Person Watts per Zone Floor Area']) >10: updated_model_api=model.parameter_batch_modification('Lights', field_label='Watts per Zone Floor Area', value=6.5, class_name=row['Name']) model=bsh.model_results(project_api_key, updated_model_api)
# re-read the lights classeslit_df=pd.DataFrame(model.get_class('Lights')) print(lit_df['Watts per Zone Floor Area'].to_string())
'''0 6.51 6.52 6.53 6.54 6.55 6.56 6.57 6.5'''

We have successfully updated all the lights class in this model programmatically!

HVAC system? No problem!

The end sue comparison has shown that HVAC consumed a lot of energy. So how about switching to another HVAC system? Currently, there are 14 HVAC system models in the HVAC design options. We can also know the information programmatically.

hvac=bshapi.measures.HVACTemplate() print(hvac.measure_help())
''' measure name: HVAC Unit: not required Minimum: 0 Maximum: 13 Type: categorical This measure will change the HVAC system in the idf file The HVAC system types are: 0. sys1: PTAC 1. sys2: PTHP 2. sys3: PSZ-AC 3. sys4: PSZ-HP 4. sys5: Packaged VAV with Reheat 5. sys6: Packaged VAV with PFP Boxes 6. sys7: VAV with Reheat 7. sys8: VAV with PFP Boxes 8. sys9: Warm air furnace, gas fired 9. sys10: Warm air furnace, electric 10. doasvrf: DOAS with variable refrigerant flow 11. doasfancoil: DOAS with Fan coils 12. doaswshp: DOAS with water source heat pump (ground as condenser) 13. doascbcb: DOAS with active cool beam + convective baseboard'''

So how about lets switch system to DOAS + VRF?

model=bsh.model_results(project_api_key, model_api_key) # set HVAC to DOAS + VRF hvac=bshapi.measures.HVACTemplate() hvac.set_data(10) updated_model_api=model.apply_measures([hvac]) # Run a new simulationnewsj=bsh.new_simulation_job(project_api_key) model=newsj.run_model_simulation(track_token=updated_model_api, track=True, unit='si') print(str(model.net_site_eui()) +" "+model.last_parameter_unit)
'''Applying measure to model: 513-7702-783987HVAC: doasvrfSubmitting simulation request...Received server responseLooking for available simulation engine... 1%Initializing model... 6%January... 22%February... 28%March... 33%April... 39%June... 50%June... 50%August... 61%September... 67%October... 72%November... 78%Writing Simulation Results... 89%Collecting Simulation Results... 94%Simulation finished successfullyCompleted! You can retrieve results using the key: 513-7702-783988158.86 kWh/m2'''

Let's also view how the VRF systems are plotted?

model.bldg_geo()

DOAS + VRF

With the help of DOAS + VRF, we successfully reduce the energy consumption from 344.77 kWh/m2 to 158.86 kWh/m2!

The BuildSim Dash can quickly plot the improvement of the model along this design. The plot implies that the DOAS + VRF system can reduce the cooling and heating energy consumption significantly. model improvement

Script to do parametric

We learned how to improve the model design by programmatically change the parameters or systems in a model based on our experiences. But what if we don't know what is good for improving energy efficiency? Typically, this can be addressed by performing a parametric study.

So can we do it through script? How fast we can develop such a script? Let's take a look!

Make a copy

First, lets find the initial model and make a copy of this model.

project_model_list=pd.DataFrame(bsh.project_model_list(project_api_key))
print(project_model_list.to_string())
# We can see now we have only one model branch under this project''' api_key branch_description branch_id branch_name branch_type last_modified_time0 d8aa9a0c-2529-4c6b-b9d2-949e0ebddf71 INIT 7702 demoProject.idf idf 2018-10-23 17:51:24'''# Request this one model branchmodel_list=pd.DataFrame(bsh.model_list(project_api_key, "d8aa9a0c-2529-4c6b-b9d2-949e0ebddf71")) print(model_list.to_string())
''' commit_date commit_id commit_msg0 2018-10-23 513-7702-783988 HVAC: doasvrf1 2018-10-23 513-7702-783987 Lights : Watts per Zone Floor Area change to: 6.52 2018-10-23 513-7702-783986 Lights : Watts per Zone Floor Area change to: 6.53 2018-10-23 513-7702-783985 Lights : Watts per Zone Floor Area change to: 6.54 2018-10-23 513-7702-783984 Lights : Watts per Zone Floor Area change to: 6.55 2018-10-23 513-7702-783983 DaylitSensor: 1.06 2018-10-23 513-7702-783982 Lights7 2018-10-23 513-7702-783981 INIT'''

The INIT stands for the initial model that we submitted, and all the others are the modifications we made through the previous practices. Let's take the commit_id of the INIT model and make a copy

init_model_id="513-7702-783981"model=bsh.model_results(project_api_key, init_model_id) bsh.copy_model(model)
project_model_list=pd.DataFrame(bsh.project_model_list(project_api_key)) print(project_model_list.to_string())
''' api_key branch_description branch_id branch_name branch_type last_modified_time0 57eb67a4-5c1e-4fbd-8c9c-74ee5b48544a INIT 7703 demoProject.idf Copied idf 2018-10-23 20:57:551 d8aa9a0c-2529-4c6b-b9d2-949e0ebddf71 INIT 7702 demoProject.idf idf 2018-10-23 17:51:24'''

Immediately, we saw two model branches are created. So now, lets work on the newly created model branch - 57eb67a4-5c1e-4fbd-8c9c-74ee5b48544a

Start a parametric agent

new_param=bsh.new_parametric_job(project_api_key)

Let's add some designs

measure_list=list()
wwr=bshapi.measures.WindowWallRatio() wwr.set_datalist([0.2, 0.6])
measure_list.append(wwr)
daylit_sensor=bshapi.measures.DaylightingSensor()
measure_list.append(daylit_sensor)
hvac=bshapi.measures.HVACTemplate()
hvac.set_datalist([1, 5, 7, 11])
measure_list.append(hvac)

There are a list of standard designs we can add to this list. But can we specify the parameters in those standard designs? For example, can we specify the control strategy in the daylight sensors? The answer is SURE!

Standard design template

# building the template# You just need to add fields that are critical in your studydaylit_template=bshapi.measures.DesignTemplate() daylit_template.set_class_label("Daylighting:Controls") daylit_template.set_template_field("Lighting Control Type", "Continuous") daylit_template.set_template_field("Minimum Input Power Fraction for Continuous Dimming Control", "0.2") daylit_template.set_template_field("Minimum Light Output Fraction for Continuous Dimming Control", "0.3")
#add the template to the designdaylit_sensor.set_custom_template(daylit_template)

Customize designs

Editing the parameters under a design is great! However, what if the things I want to change is not included in the library? For that, we can always do a customized design. There are two types of customized design:

  1. Continuous variables: design involves updating a numeric value
  2. Discrete variables: design involves updating a group of values each time.

Let's build our first continuous variable design. For example, the current infiltration design is defined by a zone/flow based method: Flow/zone, !- Design Flow Rate Calculation Method .004644, !- Design Flow Rate {m3/s} We want to change the design flow rates to 0.002644 m3/s and 0.006644 m3/s. The available infiltration design only changes the value by percentage. So we have to build one our own.

infiltration_custom_design=bshapi.measures.CustomizedMeasure('infiltration_zone', 'si') infiltration_custom_design.add_continuous_template('ZoneInfiltration:DesignFlowRate', 'Design Flow Rate', '0.004644', '0.06266')
measure_list.append(infiltration_custom_design)

Discrete design

Discrete design requires a bit of work as we are defining a group of parameters for each design. Again, let's come back to the lighting power. Let's say we have three packages of lighting systems: Fluorescent (12.0 W/m2), compact Fluorescent (8.0 W/m2 and LED (6.4 W/m2).

# Discrete custom design lit_pack_design=bshapi.measures.CustomizedMeasure('lit_pack', 'si') # we will use DiscreteMeasureOptionTemplate to assist creating a discrete design# Create template for Flourescent packagelit_template=bshapi.measures.DiscreteMeasureOptionTemplate() light_1_temp=dict() light_1_temp['Watts per Zone Floor Area'] ="12.0"lit_template.add_class_template_modify('Lights', light_1_temp) lit_template.set_option_name('FLO') # add the first template group to the design lit_pack_design.add_discrete_template_options(lit_template.get_template_group()) # Create template for Compact Flourescent packagelit_template.clear() light_2_temp=dict() light_2_temp['Watts per Zone Floor Area'] ="8.0"lit_template.add_class_template_modify('Lights', light_2_temp) lit_template.set_option_name('CFLO') # add the second template group to the design lit_pack_design.add_discrete_template_options(lit_template.get_template_group()) # Create template for LED packagelit_template.clear()
light_3_temp=dict()
light_3_temp['Watts per Zone Floor Area'] ="6.4"lit_template.add_class_template_modify('Lights', light_3_temp) lit_template.set_option_name('LED') # add the third template group to the design lit_pack_design.add_discrete_template_options(lit_template.get_template_group()) # DONE # now lets add this design back to the list measure_list.append(lit_pack_design)

Completed! Let's issue a request for a parametric run to the server. We will use the default brute-force algorithm to combine the design options. So we have:

  1. 2 designs of WWR
  2. 2 designs of daylight sensor
  3. 4 designs of HVAC
  4. 2 designs of infiltration
  5. 3 designs of lighting system

So the brute-force algorithm will automatically generate 2x2x4x2x3 = 96 models to run the parametric study.

new_param.add_model_measures(measure_list) param_study=new_param.submit_parametric_study(model_api_key=model_api_key, track=True)
'''Submitting parametric simulation job request...Received server responseYou can track the parametric using API key: 3874a72d-4ca6-48b3-b4fa-507835cd602eBuilding parametric sets generationBuilding parametric sets generationTotal progress 0%, success: 0, failure: 0, running: 3, queue: 93Total progress 0%, success: 0, failure: 0, running: 7, queue: 89Total progress 0%, success: 0, failure: 0, running: 11, queue: 85Total progress 4%, success: 4, failure: 0, running: 11, queue: 81...Total progress 11%, success: 11, failure: 0, running: 11, queue: 74...Total progress 98%, success: 95, failure: 0, running: 1, queue: 0Total progress 98%, success: 95, failure: 0, running: 1, queue: 0Total progress 100%, success: 96, failure: 0, running: 0, queue: 0Completed! You can retrieve results using the key: 186832e0-760c-4d90-872c-9b8f380f59a5'''

Just two lines of additional code, your first parametric study is on its way! Click here to see the full script of this example.

View Results

Programmatically, you can pull the results down easily - for example, the EUIs

# as our parametric run generates a new model branch id: 186832e0-760c-4d90-872c-9b8f380f59a5, we will then pull results from this idparam_id="186832e0-760c-4d90-872c-9b8f380f59a5"param_res=bsh.parametric_results(project_api_key, param_id) eui=param_res.net_site_eui() eui_pp=pp.ParametricPlot(eui) eui_df=eui_pp.pandas_df() print(eui_df.to_string())
''' DaylitSensor HVAC WWR infiltration_zone lit_pack Valuecase1 0 doasfancoil 0.6 0.06266 LED 69.40case2 0 doasfancoil 0.6 0.06266 CFLO 70.87...'''

Then, we can fully utilize python's rich plotting libraries to generate beautiful graphs like this one: results

Clone this wiki locally