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

How to model air stratification in an industrial hall?

asked 2016-12-02 03:30:50 -0600

Camille gravatar image

updated 2016-12-02 16:51:15 -0600

Hi everyone, I'm new with OpenStudio and EnergyPlus. I'm trying to do an energy simulation of an industrial hall. The height of this building is 7m so the air stratification is really important. Do you know how to deal with it? I've tried to write an energyPlus measure with the RoomAir:TemperaturePattern:ConstantGradient. Here is my code : Thank you very much for your help

    class ChangeTheRoomType < OpenStudio::Ruleset::ModelUserScript

def name
    return "Taking stratification into account"

def description
    return "Change the room type in order to model air stratification with a certain temperature gradient"

# arguments description
def argments(model)
    ThermOffset = OpenStudio::Ruleset::OSArgument::makeDoubleArgument('ThermOffset',true)
    ThermOffset.setDisplayName('Thermostat Offset')

    ReturnAirOffset = OpenStudio::Ruleset::OSArgument::makeDoubleArgument('ReturnAirOffset',true)
    ReturnAirOffset.setDisplayName('Return Air Offset')

    ExhaustAirOffset = OpenStudio::Ruleset::OSArgument::makeDoubleArgument('ExhaustAirOffset',true)
    ExhaustAirOffset.setDisplayName('Exhaust Air Offset')

    return args

#When the measure is run    
def run(model,runner,user_arguments)
    super(model, runner, user_arguments)

    # errors management
    if not runner.validateUserArguments(argumentents(model),user_arguments)
        return false

    #assign to variables
    ThermOffset=runner.getDoubleArgumentValue("ThermOffset", user_arguments)

    #Instruction in EP
    #this instruction doesnt use the arguments, it s a test
    Instruction = "
    StratProduction,  !- Name
    1,                   !- Control Integer for Pattern Control Schedule Name
    0.0,                     !- Thermostat Offset {deltaC}
    0.0,                     !- Return Air Offset {deltaC}
    1.5,                     !- Exhaust Air Offset {deltaC}
    0.5;                     !- Temperature Gradient {K/m}"

    return true
edit retag flag offensive close merge delete

3 Answers

Sort by ยป oldest newest most voted

answered 2016-12-07 11:49:38 -0600

updated 2016-12-09 10:22:28 -0600

@Camille, you made a string in your run method, but you need to add code that makes a workspace object from the string. Add the code below before the return true. Also ruby variables should start with lowercase character so change Instruction to instruction

idfObject = OpenStudio::IdfObject::load(instruction)
object = idfObject.get
wsObject = workspace.addObject(object)
new_object = wsObject.get

Optionally you can add an info message that spits back the name

runner.registerInfo("An object named '#{new_object.getString(0)}' was added.")

Then repeat this code with a new string for the additional object that @Archmage mentioned in his answer.


@Camille, in your answer you asked about the difference between an OpenStudio and EnergyPlus measure. For some background look at the digram below. The OSM is the working format for an OpenStudio model. It is what users typically work with, but it isn't what EnergyPlus needs; so prior to running a simulation we convert the OSM file to an IDF file and hand that off to EnergyPlus. If a user needs to model something, like room air models, that EnergyPlus supports but OpenStudio doesn't, an EnergyPlus measure, which is run after translation to IDF but before it is handed to EnergyPlus, will support this. The diagram also shows a third kind of measure, called a reporting measure that runs AfterEnergyPlus has run the simulation. It has access to the SQL file, the final OSM, and the final IDF. The reporting measure does have one method that runs prior to the simulation to inject output variable requests that it will need.

image description

edit flag offensive delete link more


@Camille, if you want to share this measure and have the community help develop it feel free to post it on the UnmetHours openstudio-measures repository (or I can post it if you need help). Other users can extend the measure add testing, or add argument input validation.

David Goldwasser gravatar image David Goldwasser  ( 2016-12-07 11:55:33 -0600 )edit

Thank you David ! When my measure is finished I'll share it with the community for sure! I'll ask you how to do it though :)

Camille gravatar image Camille  ( 2016-12-08 01:52:43 -0600 )edit

answered 2016-12-07 09:14:46 -0600

Archmage gravatar image

I cannot help with the OS measure, but looking at this it seems you may be missing the IDF objects called RoomAirModelType and RoomAir:TemperaturePattern:UserDefined that are also needed here to setup a zone to use the constant gradient pattern.

edit flag offensive delete link more


Thank you very much for your help ! I totally forgot about it !

Camille gravatar image Camille  ( 2016-12-08 01:47:27 -0600 )edit

answered 2016-12-08 10:42:44 -0600

Camille gravatar image

@David, I'm getting closer (at least, I hope so :) ) but I still have some problems with my E+ measure :

  • I don't understand what's the difference between OS measure and E+ measure
  • If I add a workspace object, is my measure E+ or OS?
  • How do you makeChoiceArgument for thermal spaces? I've seen that you already did it in several OS measures but I don't know how to deal with it in E+ measure. (You'll see I used one of your measure and I tried to adapt it for E+ measure ^^ but maybe I'm completely mistaken )

Could you help me? :)

Here is my code :

Thank you very much for your help

    # see the URL below for information on how to write OpenStudio measures

# start the measure
class ChangeTheRoomType < OpenStudio::Ruleset::WorkspaceUserScript

# human readable name
def name
return "ChangeTheRoomType"

# human readable description
def description
return "Take stratification into account"

# human readable description of modeling approach
def modeler_description
return "By changing the room type to constant gradient (vertical)"

def arguments(workspace)
args =

#----------------------THERMAL ZONE INTO ARGUMENTS------------------------------------------
#populate choice argument for thermal zones in the model
zone_handles =
zone_display_names =

#putting zone names into hash
zone_hash = {}
workspace.getObjectsByType("Zone".to_IddObjectType) do |zone|
  zone_hash[] = zone

#looping through sorted hash of zones do |zone_name, zone|
  zone_handles << zone.handle.to_s
  zone_display_names << zone_name

#make an argument for zones
zone = OpenStudio::Ruleset::OSArgument::makeChoiceArgument("zone", zone_handles, zone_display_names, true)
zone.setDisplayName("Choose Thermal Zones to add zone ventilation to.")
args << zone
#----------------------------NAME ARGUMENT------------------------------------------
nameRoomAirModel = OpenStudio::Ruleset::OSArgument::makeStringArgument('nameRoomAirModel', true)
nameRoomAirModel.setDisplayName('Name the pattern')
args << nameRoomAirModel

#-------------------------------TEMPERATURE INPUT INTO ARGUMENTS -------------------------------
thermOffset = OpenStudio::Ruleset::OSArgument::makeDoubleArgument('thermOffset',true)
thermOffset.setDisplayName('thermostat Offset')
args << thermOffset

returnAirOffset = OpenStudio::Ruleset::OSArgument::makeDoubleArgument('returnAirOffset',true)
returnAirOffset.setDisplayName('return Air Offset')

exhaustAirOffset = OpenStudio::Ruleset::OSArgument::makeDoubleArgument('exhaustAirOffset',true)
exhaustAirOffset.setDisplayName('exhaust Air Offset')
args << exhaustAirOffset

return args

#When the measure is run    
def run(workspace,runner,user_arguments)
super(workspace, runner, user_arguments)

# errors management
if not runner.validateUserArguments(argumentents(workspace),user_arguments)
    return false

#assign to variables
zone=runner.getOptionalWorkspaceObjectChoiceValue('zone',user_arguments, workspace)
thermOffset=runner.getDoubleArgumentValue('thermOffset', user_arguments)

#Array to hold new IDF Objects = RoomAirModelType here

#this instruction doesnt use the arguments, it s a test
string_RoomAirModelType << "
#{nameRoomAirModel} ,   ! Name
#{zone} ,               ! Zone Name (thermal zone) = user choice
AllwaysOn,          ! Availability Schedule Name = integer used need to be the same as the RoomAir:TemperaturePattern:ConstantGradient (here is 1)
Roomair Pattern 1;      ! Pattern Control Schedule Name"

#Instruction in EP
#this instruction doesnt use the arguments, it s a test
string_RoomAirModelGradient << "
StratProduction,        !- Name
1,                      !- Control Integer for Pattern Control Schedule Name
#{thermOffset},         !- Thermostat Offset {deltaC}
#{returnAirOffset} ,    !- Return Air Offset {deltaC ...
edit flag offensive delete link more



Just a note: I'm not sure why you're initializing string_RoomAirModelType as an array, but that probably will make idfObject = OpenStudio::IdfObject::load(string_RoomAirModelType) throw an error, since you're passing an array to a method that expects a string.

Eric Ringold gravatar image Eric Ringold  ( 2016-12-08 16:58:19 -0600 )edit

Good point ! Thank you :)

Camille gravatar image Camille  ( 2016-12-09 02:10:15 -0600 )edit

Haven't been able to look at this but I can check it out this weekend.

David Goldwasser gravatar image David Goldwasser  ( 2016-12-09 10:28:27 -0600 )edit

@Camille. I posted a working copy of the measure to UnmetHours GitHub repo. We don't have a lot of examples of choice objects from workspace (vs. model). It ends up being a choice argument in the run section that has the string of the workspace object name. I took two schedules that were hard coded and made them string arguments. Ideally they could be choice arguments as well, but string was easier for now since there may be a number of schedule object types vs. just a single object type

David Goldwasser gravatar image David Goldwasser  ( 2016-12-10 14:35:54 -0600 )edit

@ David, thanks a lot. I'm going to take a closer look at this! The diagram is amazing, I think I got it now, thanks again :)

Camille gravatar image Camille  ( 2016-12-12 07:22:26 -0600 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Training Workshops

Question Tools

1 follower


Asked: 2016-12-02 03:30:50 -0600

Seen: 583 times

Last updated: Dec 09 '16