1.0 Properties customization?

Hi all,

I’ve only just been dipping my toes into the new 1.0 components, but so far looks amazing as always.

I have specific question related to the new ‘properties’ object for room, models, etc… I wonder if someone can help explain?


If I would like to add some ‘custom’ properties / objects to room, face or model objects, am I right that the ‘properties’ object is the appropriate place to host these new custom objects? In that way they will sit alongside the ‘energy’ and ‘radiance’ objects already included, correct? (it seems from the reference documents here that this would be the recommended practice?)


Or would it be more appropriate to use the ‘user_data’ key back up a level on the room/face/model object itself? Is there a required / recommended place to host new user created objects so that they won’t interfere with the proper LB/HB functioning?

I was just noodling around testing to see if I could host some new custom objs on the ‘room.properties’, and while it seems to work at first, it appears that when I pass the modified rooms through another component, my new objects seem to get stripped away for some reason?

Example:
First, add a new custom object onto the room.properties object:

At first, it seems to stick:

But, once I pass the rooms through any other component, they seem to get dropped:


so I wonder:
a) Am I correct in thinking that I can host my own custom objects alongside the ‘energy’ and ‘radiance’ objs on the room.properties?
b) Am I right that using the normal setattr() is the best way to add any new custom objs to the .properties obj? Is there a built-in setter / add method for this (I didn’t see anything in there, but might have missed it?)
c) Do you know why my custom obj / key might be getting dropped from the .properties object here?


I’ve attached my sample file here. Thanks for any input! Love the new 1.0 so far - looking forward to diving in deeper.

best,
-Ed
example.gh (169.7 KB)

Hi @edpmay ,

Good question. The properties attribute that all of the honeybee geometry objects possess is exclusively meant to house attributes for honeybee extensions like honeybee-energy and honeybee-radiance. So, if you wanted to write a whole new extension for honeybee to connect to a new simulation engine, like OpenFOAM, all of the properties for each honeybee geometry object that are specific to that engine should go under a special attribute under properties. This special attribute should reference the name of the engine or the type of simulation similar to what the radiance and energy attributes currently do. So an extension for OpenFOAM might store everything under a cfd or an openfoam attribute.

Long story short, you should NOT be using the properties attribute to store your additional custom attributes unless you have an extension installed that manages those custom attributes. Without such an extension, the custom attributes will not be preserved in Honeybee objects after you duplicate/copy them (hence why you loose them when you pass them through any honeybee component that makes a copy of the object to return a new, edited object). They also will not survive serialization to JSON and reserialization back from JSON.

On the other hand, the user_data attribute is a dictionary that is meant to house whatever additional information you want. It does not have to be associated with a honeybee extension and the dictionary will be copied every time that the parent Honeybee geometry object is duplicated. So, this way, any information in the dictionary will be preserved as you pass it through components that copy the honeybee object and return a new edited object. Additionally, the data under the user_data key will be preserved when you write the parent honeybee object into a JSON file or string and then re-serialize the JSON back to a Python object. There is one caveat for this JSON serialization, however, which is that the attributes that you put in the user_data dictionary should be JSON-serializable. This means you should not put Python objects in the user_data dictionary unless you first serialize those objects to dictionaries before you add them.

I hope that helps clarify everything.

Thanks so much @chris, that is super helpful to understand better.

So yes: I’ll keep my monkeying around limited to the ‘user_data’ field in the future - that all makes sense.

I was able to make that work no problem.

Briefly: lets say that I did want to pass along a more complex object with the geometry? In that case, it appears that I can make that work by using the ‘user_data’ to store the object’s attributes, and then simple re-construct the object as needed at a later point. Do you think there would be any issue with this process as regards the serialization or other HB routines here? I don’t want to mess anything up with the core LB/HB processes. Seems to be working so far though?

So something like:


Make a new object, and then put the obj’s attributes into the ‘user_data’ dict:

Pass all that along the HB chain… At some later point, pull that data back out and re-build the object:


I think I can probably make that work for what I’m doing here. But if there is anything there which you see that would mess with the LB/HB process I of course appreciate any advice / pointers there.

thanks as always!
@edpmay

example.gh (111.9 KB)

Hi @edpmay ,

What you have done here is certainly acceptable and playing by the rules of the core libraries. You can see that your custom attributes make it into the JSON version of the object so they will also be serialized back:

I might have a couple of suggestions to make your implementation a little cleaner:

  1. While vars and dict will work well for simple classes like yours, we tend to write explicit methods for to_dict and from_dict on our own Ladybug Tools workflows. For example, here’s a to_dict and a from_dict method for a simple EnergyPlus opaque material. This allows us to keep the dictionary representation a bit lighter (since we don’t write in hidden attributes) and it also allows us assign default variables if they are not specified in the dictionary.
  2. Because all other developers have the ability to write their own attributes into the user_data dictionary, you may want to keep your specific ones under their own key within the user_data dictionary. This will help minimize the case that another developer accidentally overwrites your attributes. Organizing things under one key also sets you up to turn your objects into an official honeybee extension if you ever wanted to do this.

thank so much @chris, that is very helpful and I will be sure to follow your advice there on the _to_dict() and _from_dict() custom methods as I move forward.

And yes, I will be sure to try and segment off my new elements within a namespace key - that makes a lot of sense.

thanks for the pointers and input!
@edpmay

1 Like