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

Force measure to assign string to field, whether or not the string is valid or invalid?

asked 2018-07-23 18:53:46 -0600

mldichter gravatar image

updated 2018-07-26 17:27:12 -0600

I am writing a fairly large measure and I'm having trouble getting the generated idf to have all the fields populated.

The problem is the measure does not set an object field to a string if that string is invalid. For example, if I'm trying to create a Sizing:Plant object with the following fields without having first created the Plant object

Sizing:Plant,
    NameOfPlantObjectThatDoesNotExistYet,             !- Plant or Condenser Loop Name
    Heating,                 !- Loop Type
    82,                      !- Design Loop Exit Temperature {C}
    11.0;                    !- Loop Design Temperature Difference {deltaC}

the text in the idf file created by the measure looks like this

Sizing:Plant,
    ,                        !- Plant or Condenser Loop Name
    Heating,                 !- Loop Type
    82,                      !- Design Loop Exit Temperature {C}
    11.0;                    !- Loop Design Temperature Difference {deltaC}

The solution is very simple. Always create an object before referencing it. However, this is really annoying since you now have to worry about the order of adding objects in the measure.

Is there any way to force the measure to write a value to an object field, even if that string is invalid according to Energyplus?


Failed Fix #1:
Looks like there is no easy way to do what I want. However, I did find a boneheaded way to do it. I start with adding all the idf objects as strings directly from the idf file

# define what happens when the measure is run
def run(workspace, runner, user_arguments)
  super(workspace, runner, user_arguments)

  # use the built-in error checking
  if !runner.validateUserArguments(arguments(workspace), user_arguments)
    return false
  end

  #array to hold new IDF objects
  string_objects = []

  string_objects << "
  AirLoopHVAC,
      DOAS,                    !- Name
      DOAS Controllers,        !- Controller List Name
      DOAS Availability Managers,  !- Availability Manager List Name
      autosize,                !- Design Supply Air Flow Rate {m3/s}
      DOAS Branches,           !- Branch List Name
      ,                        !- Connector List Name
      DOAS Air Loop Inlet,     !- Supply Side Inlet Node Name
      DOAS Return Air Outlet,  !- Demand Side Outlet Node Name
      DOAS Supply Path Inlet,  !- Demand Side Inlet Node Names
      DOAS Supply Fan Outlet;  !- Supply Side Outlet Node Names
      "
  .
  .
  .
  MANY MORE OBJECTS ADDED TO string_objects
  .
  .
  .
  DONE ADDING OBJECTS

  #multiple times so objects that reference other objects can fill fields since all objects exist from first pass
  for i in 1..2
    string_objects.each do |string_object|
      create_object(string_object,workspace)
    end
  end

  return true
end

where the create_objects() function is

  def create_object(idf_object_string,workspace)
    idf_object_array = idf_object_string.split(/[\n,;]/)
    idf_object_array = idf_object_array[1..-3]
    field_array = []
    idf_object_array.each do |element|
      element = element.strip
      if !( element.index("!") or element == "")
        field_array.push(element)
      end
    end

    object = get_object(field_array[1],field_array[0],workspace)
    for i in 2..(field_array.length-1)
      object.setString(i-1,field_array[i])
    end

    return true
  end

The first chunk is to extract all the objects field values from the inputted idf_object_string. The second chunk is to create that object. The get_object() function finds the object with a certain name or type, and creates that object if it doesn't exist.

This is kinda boneheaded, but it is working, almost. The first chunk for parsing the idf_object_string in create_object() doesn't work with blank fields, like the Connector List ... (more)

edit retag flag offensive close merge delete

Comments

I'm doing something similar and here's my approach. Instead of your create_object method, you should be able to use this within your string_objects.each do loop:

new_idf_object = OpenStudio::IdfObject::load(idf_object_string)

new_object = new_idf_object.get

workspace.addObject(new_object)

This should create the idf objects with all string contents, regardless of whether or not the dependent objects exist. Only lines not included in the idd will be disregarded.

kheine gravatar imagekheine ( 2018-07-25 12:07:22 -0600 )edit

@kheine I think I did that, but it still didn't work. I also tried using

workspace.setStrictnessLevel("None".to_StrictnessLevel)

to no avail. Maybe I did something wrong. Have you explicitly tried adding the object I had difficulty with?

Sizing:Plant,
    NameOfPlantObjectThatDoesNotExistYet,        !- Plant or Condenser Loop Name
    Heating,                 !- Loop Type
    82,                      !- Design Loop Exit Temperature {C}
    11.0;                    !- Loop Design Temperature Difference {deltaC}

I very much hope I'm wrong and you're right.

mldichter gravatar imagemldichter ( 2018-07-26 15:18:04 -0600 )edit
1

@kheine I finally figured it out. Not saying your solution is wrong (my code is a mess right now so it's anyone's guess what works and what doesn't) but I did find a very simple solution to the invalid field difficulty I was having. It's in my answer below. Just wanted to let you know in case it's useful to your.

And I also wanted to thank you for taking the time to answer!

mldichter gravatar imagemldichter ( 2018-07-27 15:56:03 -0600 )edit

1 Answer

Sort by ยป oldest newest most voted
2

answered 2018-07-27 15:51:55 -0600

mldichter gravatar image

As usual, the solution is really easy once you know how to do it. Here's the code

# define what happens when the measure is run
def run(workspace, runner, user_arguments)
  super(workspace, runner, user_arguments)

  # use the built-in error checking
  if !runner.validateUserArguments(arguments(workspace), user_arguments)
    return false
  end

  #array to hold new IDF objects
  string_objects = []

  string_objects << "
  AirLoopHVAC,
      DOAS,                    !- Name
      DOAS Controllers,        !- Controller List Name
      DOAS Availability Managers,  !- Availability Manager List Name
      autosize,                !- Design Supply Air Flow Rate {m3/s}
      DOAS Branches,           !- Branch List Name
      ,                        !- Connector List Name
      DOAS Air Loop Inlet,     !- Supply Side Inlet Node Name
      DOAS Return Air Outlet,  !- Demand Side Outlet Node Name
      DOAS Supply Path Inlet,  !- Demand Side Inlet Node Names
      DOAS Supply Fan Outlet;  !- Supply Side Outlet Node Names
      "
      .
      .
      .
      MANY MORE OBJECTS ADDED TO string_objects
      .
      .
      .
      DONE ADDING OBJECTS

  idfobjects_vector = []
  string_objects.each do |string_object|
    idfObject = OpenStudio::IdfObject::load(string_object)
    object = idfObject.get
    idfobjects_vector.push(object)
  end
  workspace.addObjects(idfobjects_vector)

  return true
end

The significant difference was using addObjects() PLURAL instead of addObjects() SINGULAR.

The loop converts all the IDF objects in text file format to IDFObjects objects and puts all those IDFObjects into a vector called idfobjects_vector. The idfobjects_vector is then passed to the addObjects() PLURAL outside the loop.

I'm guessing that addObject(idf_object) SINGULAR function checks the validity of all fields of the idf_object being added to the IDF every time. Fields that were invalid were left blank. On the other hand, the addObjects(idfobjects_vector) PLURAL still checks the validity of all the objects being added, but is checking field validity of all objects at once, instead of one at a time like my previous attempts. This means the order of the objects written in text format in the measure does not matter, which is very, VERY nice for the severely interconnected airloops, plantloops, etc.

edit flag offensive delete link more

Comments

You are correct in all your analysis. Workspace::addObject (singular) checks validity for each object sequentially, addObjects (plural) considers all of the objects together. AddObjects is much easier if you are adding many objects at once. The IdfFile and IdfObject classes do not consider relationships between objects and will allow you to set strings referring to objects that don't yet exist. I added this issue on the OpenStudio github site to discuss possible ideas for tweaking this feature in the future.

macumber gravatar imagemacumber ( 2018-11-19 13:33:00 -0600 )edit

@macumber The major disadvantage though is if one of the objects in the vector input to workspace.addObjects() is invalid, then none of the objects in the input vector are added, and workspace.addObjects() returns an empty vector. This makes debugging pretty annoying as all you know is there is at least one problem with an object in the input vector.

mldichter gravatar imagemldichter ( 2018-11-19 15:00:40 -0600 )edit
mldichter gravatar imagemldichter ( 2018-11-19 15:33:23 -0600 )edit

Your Answer

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

Add Answer

 

Question Tools

1 follower

Stats

Asked: 2018-07-23 18:53:46 -0600

Seen: 111 times

Last updated: Jul 27 '18