Cooling-Period Losses & Gains (kWh) |
We're always on the lookout for new ways to work with our tools and get them to interact better with one another. Like most designers, we can often use 5 or 10 different pieces of software for any given job. Two of our favorites are PHPP (the Passive House Planning Package Energy modeling software) and Sketchup - the simple 3D Modeler. While we certainly love the 3DMaxe-s and V-Ray-s of the world, Sketchup has a definite place in our workflow,, especially when it comes to the diagram. The simple line-work and flexibility of the modeler make Sketchup a great tool for simple 3D diagrams.
Recently we've begun working with Ruby to interact with Sketchup a bit more. I caution you - we're in no ways experts in (or even all that good at) Ruby, but we thought we'd post a bit about one of our recent tools we made. This script uses Ruby to import values, calculated in the PHPP Energy Modeling software, and then apply them as attributes to 3D Geometry in Sketchup.
This, of course, will probably all be entirely obsolete as soon as they release the PHPP Sketchup tool DesignPH (though who knows when that will ever happen in the US ..... ) But for now this is a nice way to perform both data verification (by using color to spot abnormalities and errors) and to display information to clients and others working on the project.
PHPP is an incredibly robust energy modeling package, but of course its completely devoid of any graphical content save for a couple little graphs and a chart or two buried in there. While you engineers out there might love that kind of thing, those of us on the more architect-y end of the spectrum can have a tough time with nothing but page after page of numbers. Its also often difficult to translate this data into something meaningful for our clients or design-partners.
recently, out of necessity we built a pair of Ruby scripts which can take some of this mush of data and bring it into Sketchup. The image at the top of this post shows you the kind of thing we're after - using visuals to more intuitively show energy performance in a flexible way which allows us to move quickly through multiple versions and options.
So - how does it work?
First, the data in PHPP needs to be consolidated into an export sheet. While the 'Windows' sheet does a decent enough job giving some info about the window performance - we actually like to get a finer grain of feedback separately for the heating (winter) and cooling (summer) periods for our analysis.
The image below is from one of our custom sheets from a recent project - its mostly all reporting from different locations within PHPP (sort of), but collected in one place so we can more effectively assess the window performance.
Custom sheet Heating Period Reporting Table |
Once you set this up for the heating and cooling periods, you can pull out whatever data your interested in. In this case, its the Window Heating and Cooling Period's Net Gain (or Loss) values. These are exported to a simple CSV file which is what we use to move data into Sketchup.
CSV of the Data we want to bring into Sketchup - these numbers are all kWh / period |
Ok - so far pretty easy right? Its just messing around in Excel really. So now that you have the CSV, we move to Ruby. We are still learning Ruby - so please don't yell at us if (when) you see us doing something not quite right.
The Sketchup workflow actually has two scripts - one which imports data, and the other which colors elements
First, we select the PHPP CSV Importer tool from the plugins menu...
Next enter the path for the CSV file you just saved out from the PHPP Excel model.
Enter the CSV columns for the data types you are importing (column 1 in the CSV is column 0 in the ruby here) - yes, this is all pretty User-Unfriendly - you need to know a lot about how the data is set up before this can work - I'll build it out so its nicer to work with . . . someday. . .
This now takes the data and applies it to the model. It basically looks around at the objects and matches the names of the objects in the Sketchup model with the Names on the CSV list. The code looks like this:
mod = Sketchup.active_model # Open model
ent = mod.entities # All entities in model
sel = mod.selection # Current selection
#This is the Method to call for importing data
def PHPP_CSV_Importer.assignAttribute(imported_array, column, attrib_name)
mod = Sketchup.active_model # Open model
ent = mod.entities # All entities in model
sel = mod.selection # Current selection
_imported_data_array = imported_array
_column = column
_attrib_name = attrib_name
#This part ‘clears’ all the existing attribute values
ent.each do |e|
e.set_attribute("dynamic_attributes", _attrib_name, 0)
end
#This part steps through every Entity (in Ruby, all Sketchup objects are called 'Entities'
ent.each do |e|
entName = e.get_attribute("dynamic_attributes", "_name")
limit = _imported_data_array.length
i = 0
j = 0
for counter in 0..limit-1
if entName == _imported_data_array[j][0]
_importedValue = _imported_data_array[j][_column]
e.set_attribute("dynamic_attributes", _attrib_name, _importedValue.chomp.to_i )
j+=1
else
j+=1
end
end
end
end
#Below this is what runs when you select from the PLUGINS menu
#This part is to get the file location and Columns for import
prompts = ["File Location", "Heating Col.", "Cooling Col.", "Yearly Col."]
defaults = ["/Users/edwinmay/Desktop/Workbook1.csv", "1", "2", "3"]
inputValue = UI.inputbox(prompts, defaults, "File to Import")
heatingCSVcolumn = inputValue[1].chomp.to_i
coolingCSVcolumn = inputValue[2].chomp.to_i
yearlyCSVcolumn = inputValue[3].chomp.to_i
#This part tells where the file to read is
fname = "/Users/edwinmay/Desktop/Workbook1.csv" #inputValue[0]
f = File.new(fname, "r");
lines = f.readlines(); #This makes an array of each line - each line is a string
f.close();
#This part splits the imported file(array) into a 2D array at the commas
imported_data_array = []
lines.each { |r|
line_array = []
line_array = r.split(',')
imported_data_array << line_array
}
###########
# Main body of the Program - definition calls
###########
assignAttribute(imported_data_array, heatingCSVcolumn, "summernet")
assignAttribute(imported_data_array, coolingCSVcolumn, "winternet")
assignAttribute(imported_data_array, yearlyCSVcolumn, "yearnet")
end
end
As you can see, this will make attributes and apply the imported values. So far so good right? But still no colors yet. But f you look at any of the window objects you'll see that the values have been applied.
Attributes from PHPP applied to the 3D Geometry as an attribute |
So, if you select the windows or elements you want to colorize, then select the PHPP Visualizer from the plugins menu, you should be prompted which period you want to see - simple select one and the colors will be applied and show up. You can run this as many times as you like and it will re-style everything accordingly.
Select the PHPP Visualizer Tool from the Menu |
Select the Period you want to see represented |
For those interested, the code for the Visualizer looks like this:
###########
# VARIABLES
###########
module PHPP_Vis
def PHPP_Vis.main
mod = Sketchup.active_model # Open model
ent = mod.entities # All entities in model
sel = mod.selection # Current selection
maxCount = sel.count-1
maxSumNetGains = 1810
maxSumNetLosses = 330
maxWintNetGains = 1070
maxWintNetLosses = 400
maxNetGains = 2870
maxNetLosses = 640
inputValue = []
textArray = []
###########
# METHODS
###########
#method for displaying the Summer Net Gains/Losses of selected entities
def PHPP_Vis.displaySumNet(sumNetGains, sumNetLosses)
mod = Sketchup.active_model
maxNetGains = sumNetGains
maxNetLosses = sumNetLosses
sel = mod.selection
sel.each do |e|
netValue = e.get_attribute("dynamic_attributes", "summernet")
if netValue > 0
r = 255
g = 255-(((netValue)*255) / maxNetGains)
b = 255-(((netValue)*255) / maxNetGains)
else
r = 255+(((netValue)*255) / maxNetLosses)
g = 255+(((netValue)*255) / maxNetLosses)
b = 255
end
e.material = r,g,b
end
end
#method for displaying the Winter Net Gains/Losses of selected entities
def PHPP_Vis.displayWintNet(wintNetGains, wintNetLosses)
mod = Sketchup.active_model
maxNetGains = wintNetGains
maxNetLosses = wintNetLosses
sel = mod.selection
sel.each do |e|
netValue = e.get_attribute("dynamic_attributes", "winternet")
if netValue > 0
r = 255
g = 255-(((netValue)*255) / maxNetGains)
b = 255-(((netValue)*255) / maxNetGains)
else
r = 255+(((netValue)*255) / maxNetLosses)
g = 255+(((netValue)*255) / maxNetLosses)
b = 255
end
e.material = r,g,b
end
end
#method for displaying the Yearly Net Gains/Losses of selected entities
def PHPP_Vis.displayNet(netGains, netLosses)
mod = Sketchup.active_model
maxNetGains = netGains
maxNetLosses = netLosses
sel = mod.selection
sel.each do |e|
netValue = e.get_attribute("dynamic_attributes", "yearnet")
if netValue > 0
r = 255
g = 255-(((netValue)*255) / maxNetGains)
b = 255-(((netValue)*255) / maxNetGains)
else
r = 255+(((netValue)*255) / maxNetLosses)
g = 255+(((netValue)*255) / maxNetLosses)
b = 255
end
e.material = r,g,b
end
end
#method for displaying Attribute Value on the Selected Elements
def PHPP_Vis.displayText(inputValue)
mod = Sketchup.active_model
ent = mod.entities
sel = mod.selection
_inputValue = inputValue
#This part applies the attribute value to the face
sel.each do |e|
textToDisplay = e.get_attribute("dynamic_attributes", _inputValue)
face = sel
cntrPoint = e.bounds.center
point = Geom::Point3d.new cntrPoint
vector = Geom::Vector3d.new(10,10,10) #the 10,10,10 part should use the normal to ‘push'
pointNew = point.offset! vector
text = ent.add_text textToDisplay, point
end
end
#This part ‘clears’ the material colors from the last run
ent.each do |e|
e.material = 255,255,255
end
#Input Box def inPutBox
prompts = ["Display"]
defaults = [" "]
list = ["Summer Net|Winter Net|Yearly Net"]
inputValue = UI.inputbox(prompts, defaults, list, "Display")
#Main Body of the Program that calls functions to color faces
_inputValue = inputValue[0]
if _inputValue == "Summer Net"
displaySumNet(maxSumNetGains, maxSumNetLosses)
#displayText("summernet")
elsif _inputValue == "Winter Net"
displayWintNet(maxWintNetGains, maxWintNetLosses)
elsif _inputValue == "Yearly Net"
displayNet(maxNetGains,maxNetLosses)
end
end
end
As you can see, there a bunch of hard-coded elements that should be more flexible (things like adjusting the scale max and min, etc..) Maybe someday I'll get to it. For now I just change the code depending on the data coming in. Hasn't been a huge pain.... yet.
Mostly its pretty simple though - normalizes the value from the attribute and uses a color scale to select the color value in R,G and B - then applies that color to the face.
Colorized Windows and Doors based on values calculated in PHPP |
It works pretty well and we've used it for the last couple projects. It could certainly use some 'making-nice', but it gives us the feedback we need for these kinds of projects. One side benefit is that you instantly note outliers / errors easily in this workflow because they visually stick out like a sore thumb.
And while it may not seem like much when your looking at a single small house with 15 windows, once you get to the larger multifamily or commercial jobs tools like this become critical. We have one Passive House in the pipeline with 70+ windows and you wouldn't want to go applying data by hand every time you made a change.
If you think you have a better idea for the code or the procedures here let us know! We're always refining things and love to hear new ideas.