Question-and-Answer Resource for the Building Energy Modeling Community
Get started with the Help page
Ask Your Question

Revision history [back]

I often end up not using the makeChoiceArgumentOfWorkspaceObject, and instead use a custom version of makeChoiceArgument that gives me more control of sort and filtering. Below is an example for light definitions. Note that the handle is what is passed to the run section, vs. the display name

#populate choice argument for lights_defs that are applied to surfaces in the model
lights_def_handles = OpenStudio::StringVector.new
lights_def_display_names = OpenStudio::StringVector.new

#putting space types and names into hash
lights_def_args = model.getLightsDefinitions
lights_def_args_hash = {}
lights_def_args.each do |lights_def_arg|
  lights_def_args_hash[lights_def_arg.name.to_s] = lights_def_arg
end

#looping through sorted hash of lights_defs
lights_def_args_hash.sort.map do |key,value|
  #only include if it is used in a space, and has a non 0 value
  if value.quantity > 0 and not value.wattsperSpaceFloorArea.empty?
    lights_def_handles << value.handle.to_s
    lights_def_display_names << key
  end
end

#make an argument for lights_def
lights_def = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("lights_def", lights_def_handles, lights_def_display_names,true)
lights_def.setDisplayName("Choose a Watt per Area Lights Definition to Add Costs to.")
args << lights_def

Below is what would be in the run section

#assign the user inputs to variables
lights_def = runner.getOptionalWorkspaceObjectChoiceValue("lights_def",user_arguments,model) #model is passed in because of argument type

#check the Definition for reasonableness
if lights_def.empty?
  handle = runner.getStringArgumentValue("lights_def",user_arguments)
  if handle.empty?
    runner.registerError("No Lights Definition was chosen.")
  else
    runner.registerError("The selected Lights Definition with handle '#{handle}' was not found in the model. It may have been removed by another measure.")
  end
  return false
else
  if not lights_def.get.to_LightsDefinition.empty?
    lights_def = lights_def.get.to_LightsDefinition.get
  else
    runner.registerError("Script Error - argument not showing up as Lights Definition.")
    return false
  end
end  #end of if lights_def.empty?

@macumber may have examples on how to use the makeChoiceArgumentOfWorkspaceObjects. I think it handles sorting now by object name, if you don't want to filter it.

To address you question of selecting multiple objects, there are a few possible solutions, none of the very pretty.

  1. You can make a string argument where you have to know and enter the object names comma seperated. Then in the run section you can parse the string and find the objects.
  2. We have played around with the idea of a measure that would for example create bool arguments for each thermal zone, in the model, then you could check as many as you want to apply the measure two. This would actually look pretty nice, but wouldn't be as manageable in very large models. If you want to do a large parametric analysis having an unknown amount of user arguments could become problematic. If that isn't in your use case, you could do this direction.
  3. Sometimes I add the building object into the choice list. If that is chosen I use it as an "Apply to all" option. But that still is a 1 or all solution. You can't pick 3 items out.
  4. The last one is more of a future option. If you have used the SketchUp plugin, you are aware user scripts such as the window to wall ratio. It takes in your current selection and applies the script to that selection. OpenStudio 1.7.0 now has multi-select capability. While there is no timeline, we have talked about giving measures access to the apps currently selected objects. This would of course only work in apply measures now vs. in a parametric study.

Update:

Option 1 would look something like this.

# argument would be something like "Zone 1,Zone 2,Zone 3,Zone 4"
example_argument= runner.getStringArgumentValue("example_argument",user_arguments)

# split string into an array of selected thermal zone names
selected_zone_names = example_argument.split(",")

# add thermal zones from argument to array
selected_zone_objects = []
model.getThermalZones.each do |thermal_zone|
  if selected_zone_names.include? thermal_zone.name.to_s
    selected_zone_objects << thermal_zone
  end
end

# add warning if there two arrays are not the same size
if selected_zone_names.size > selected_zone_objects.size
  runner.registerWarning("One or more of the entered zone names could not be found in the model.")
end