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

Revision history [back]

This is because thermalZone.airLoopHVACTerminal returns an optional.

Try this:

thermalZones = model.getThermalZones

thermalZones.each do |thermalZone|
  supplyTerminal = thermalZone.airLoopHVACTerminal
  if supplyTerminal.empty?
    runner.registerInfo("Cannot find an airloop terminal for #{thermalZone.name}")
  else
    supplyTerminal = supplyTerminal.get
    runner.registerInfo("For '#{thermalZone.name}' the supply terminal '#{supplyTerminal}' was found.")
  end
end

This is because thermalZone.airLoopHVACTerminal returns an optional.

Try this:

thermalZones = model.getThermalZones

thermalZones.each model.getThermalZones.each do |thermalZone|
|zone|
  supplyTerminal = thermalZone.airLoopHVACTerminal
zone.airLoopHVACTerminal
  if supplyTerminal.empty?
    runner.registerInfo("Cannot find an airloop terminal for #{thermalZone.name}")
  else
    supplyTerminal = supplyTerminal.get
    runner.registerInfo("For '#{thermalZone.name}' the supply terminal '#{supplyTerminal}' '#{supplyTerminal.name}' was found.")
  end
end

This is because thermalZone.airLoopHVACTerminal OpenStudio::Model::ThermalZone::airLoopHVACTerminal() returns an optional.optional HVACComponent, see SDK doc. You have to get it first.

Try this:

model.getThermalZones.each do |zone|
  # this returns an optional HVACComponent
  supplyTerminal = zone.airLoopHVACTerminal
  if supplyTerminal.empty?
    runner.registerInfo("Cannot find an airloop terminal for #{thermalZone.name}")
  else
    supplyTerminal = supplyTerminal.get
    runner.registerInfo("For '#{thermalZone.name}' the supply terminal '#{supplyTerminal.name}' was found.")
  end
end

Like I said supplyTerminal, even after ".get" will be an HVACComponent, not an actual object such as OpenStudio::Model::AirTerminalSingleDuctUncontrolled for example. If you need to work with the actual underlying object, you'll have to cast it into what it's really.

The clean way is to use to_XXXX method, but you have to test potentially a lot of cases...

if supplyTerminal.to_AirTerminalSingleDuctUncontrolled.is_initialized
  supplyTerminal = supplyTerminal.to_AirTerminalSingleDuctUncontrolled.get
elsif supplyTerminal.to_AirTerminalSingleDuctVAVNoReheat.is_initialized
  supplyTerminal = supplyTerminal.to_AirTerminalSingleDuctVAVNoReheat.get
else
  runner.registerInfo("I don't know what this object is because there are too many possible ones!")
end

You want the dirty way? I knew it! But I shall not be liable for any problems you might get :)

Anyways, just add this method to the class ModelObject...

# Extend ModelObject class to add a to_actual_object method
# Casts a ModelObject into what it actually is (OS:Node for example...)
class OpenStudio::Model::ModelObject
  def to_actual_object
    obj_type = self.iddObjectType.valueName
    obj_type_name = obj_type.gsub('OS_','').gsub('_','')
    method_name = "to_#{obj_type_name}"
    if self.respond_to?(method_name)
      actual_thing = self.method(method_name).call
      if !actual_thing.empty?
          return actual_thing.get
      end
    end
    return false
  end
end

Then you can do supplyTerminal = supplyTerminal.to_actual_object

It'll work with anything, since everything in OpenStudio::Model is after all a ModelObject: ModelObject instances, HVACComponent, even objects such as AirTerminalSingleDuctVAVNoReheat themselves (though that's completely pointless)

This is because OpenStudio::Model::ThermalZone::airLoopHVACTerminal() returns an optional HVACComponent, see SDK doc. You have to get it first.

Try this:

model.getThermalZones.each do |zone|
  # this returns an optional HVACComponent
  supplyTerminal = zone.airLoopHVACTerminal
  if supplyTerminal.empty?
    runner.registerInfo("Cannot find an airloop terminal for #{thermalZone.name}")
  else
    supplyTerminal = supplyTerminal.get
    runner.registerInfo("For '#{thermalZone.name}' the supply terminal '#{supplyTerminal.name}' was found.")
  end
end

Like I said supplyTerminal, even after ".get" will be an HVACComponent, not an actual object such as OpenStudio::Model::AirTerminalSingleDuctUncontrolled for example. If you need to work with the actual underlying object, you'll have to cast it into what it's really.

The clean way is to use to_XXXX method, but you have to test potentially a lot of cases...

if supplyTerminal.to_AirTerminalSingleDuctUncontrolled.is_initialized
  supplyTerminal = supplyTerminal.to_AirTerminalSingleDuctUncontrolled.get
elsif supplyTerminal.to_AirTerminalSingleDuctVAVNoReheat.is_initialized
  supplyTerminal = supplyTerminal.to_AirTerminalSingleDuctVAVNoReheat.get
else
  runner.registerInfo("I don't know what this object is because there are too many possible ones!")
end

You want the dirty way? I knew it! But I shall not be liable for any problems you might get :)

Anyways, just add this method to the class ModelObject...

# Extend ModelObject class to add a to_actual_object method
# Casts a ModelObject into what it actually is (OS:Node for example...)
class OpenStudio::Model::ModelObject
  def to_actual_object
    obj_type = self.iddObjectType.valueName
    obj_type_name = obj_type.gsub('OS_','').gsub('_','')
    method_name = "to_#{obj_type_name}"
    if self.respond_to?(method_name)
      actual_thing = self.method(method_name).call
      if !actual_thing.empty?
          return actual_thing.get
      end
    end
    return false
  end
end

Then you can do supplyTerminal = supplyTerminal.to_actual_object

It'll work with anything, since everything in OpenStudio::Model is after all a ModelObject: ModelObject instances, HVACComponent, even objects such as AirTerminalSingleDuctVAVNoReheat themselves (though that's completely pointless)