Dragonfly/Ladybug: Potential Bugs and Question

Hi,

I’ve been looking through the code for various Dragonfly and Ladybug components, and I’ve run into a few lines of code that I think might have been meant to be written differently. Apologies if I am mistaken.

The first occurs in the code behind the DF Dragonfly component, in the Vegetation class’s init method. Line 1880 initializes self._s_trees = is_trees, but there are no getter and setter methods for the property _s_trees, only for is_trees. I’m wondering if self._s_trees was meant to be self.is_trees?

The second is also in the DF Dragonfly code, in the VegetationPar class’s setter method for self.vegetation_start_month. On line 2115, self._vegetation_start_month is always set to 0 regardless of whether or not the user entered a valid vegetation start month. Should there be an else before line 2115 like there is for the vegetation_end_month setter?

The third is in the code supporting the DF Run UWG component, in the set_uwg_input method. On line 170, if DFCity.vegetation_parameters.vegetation_start_month == 0, uwg.vegEnd = vegEnd, but according to the logic used in lines 166-167, shouldn’t uwg.vegEnd be initialized to the epw default value only if the user entered a 0 for DFCity.vegetation_parameters.vegetation_end_month (check for end month instead of start month)?

The fourth is in the Ladybug_Ladybug component’s Preparation class, in the epwLocation method. Should the second to last line of the method reading epwfile.close actually read epwfile.close()?

Lastly, I just had a quick question. I noticed that in the code for the DF Run UWG component, in the autocalcStartEndVegetation method, on line 94, vegEnd is initialized to 12. However, vegStart is not initialized to any value. This means that if we’re looking at weather data for an area for which no month’s average hourly temperature is above 10 degrees Celsius, returning an uninitialized vegStart value would raise an error? I ask this because I’m unsure whether or not we can trust that every location for which epw files exist definitely have average hourly temperature greater than 10 for at least one month.

Thanks so much!

@annasong,

At first glance, each of your comments seems to be an actual bug. I would suggest we break these out into two git issues for the respective repo on git:

Dragonfly: https://github.com/chriswmackey/Dragonfly
Ladybug: https://github.com/mostaphaRoudsari/ladybug

You may already know this, but FYI in github you can link to specific lines of codes (https://help.github.com/articles/creating-a-permanent-link-to-a-code-snippet/) which I think would make your life easier.

Thanks for finding these bugs,

S

1 Like

Hi @SaeranVasanthakumar,

Just finished posting in issues on the two GitHub pages. I actually didn’t know about the permalink function. Thanks for the suggestion!

1 Like

Hi @SaeranVasanthakumar,

I’ve continued to look through the Dragonfly component code and have come to a few more questions.

  1. Line 1564 of DF Dragonfly reads
self._bldg_types.append(_bldg_program + ',' + _bldg_age)

However, I can’t seem to find where else self._bldg_types is mentioned? If self._bldg_types isn’t defined anywhere, what variable did this line intend to append the string (program + age) to? This line occurs in function

@bldg_type_ratios.setter
def bldg_type_ratios(self, bldg_type_dict):

It seems that the reason that the reference to self._bldg._types doesn’t throw an error is that this function is never called.

  1. When creating a city, typologies of the same program and age are merged. During the merging process, it seems that properties of the original typologies being merged: roof albedo and roof vegetation fraction (if entered by the user instead of taking the default values), aren’t remembered by the new merged typology? Is this because these properties are relatively unimportant and don’t make a big difference in the overall city?

  2. I have a copy of UWG.py saved in Desktop\urbanWeatherGen-master\UWG that’s slightly different from the UWGs in the Dragonfly-master\UWG and Rhinoceros\6.0\scripts\UWG folders. When I run the DF Run UWG component, the

from UWG import UWG

line occasionally imports the urbanWeatherGen-master UWG file instead of the one from the Rhino scripts library, resulting in an error because the program expects the latter. I’ve tried importing sys and changing sys.path to try to import the UWG file in Rhino scripts without success.

(However, this only happens infrequently, and all other times, the Rhino scripts version is imported. If the wrong version is imported, closing and reopening Rhino will usually fix the issue and the correct version will be imported the second time around.)

Is there any way to control via code which UWG file is imported rather than relying on closing and reopening Rhino to get the correct version?

Thanks so much.

@annasong

I’ll need some time to look into questions 1 and 2, or @chris will respond when he has time, but I can take a stab at answering question 3.

So for some reason the IronPython interpreter is choosing the path to your Desktop UWG, rather then using your Rhino scripts folder exclusively. I believe the way the sys.path works in Python, it selects the first UWG folder it finds in the list of all directories in sys.path. And in this case Rhino adds the scripts folder to the list of directories for IronPython to search in the sys.path when it starts. At some point, I assume you are adding your desktop directory to the sys.path, which is why the interpreter is going there to find the UWG, before going to the Rhino scripts folder.

You can confirm this by printing your sys.path, and you should see the desktop directory there before (i.e at a lower index) then the Rhino scripts directory.

I’m not sure how the UWG from your desktop is getting added there but a couple of things to check out:

  • If you are running the desktop UWG at any point, while you have Rhino open, you might be using the same interpreter, which is therefore inserting it’s path before the Rhino scripts path.
  • You may have added your desktop or related directory to the top of your to the environment variable PYTHONPATH i.e like so:
    .
    (Caveat, this is for Cpython, but I think similiar for IronPython.

So making sure to insert the correct path to the Rhino scripts version at index 0, should fix this.

Is this what you tried with the sys library?

sys.path.insert(0, 'C:\\Users\\%User%\\AppData\\Roaming\\McNeel\\Rhinoceros\\6.0\\scripts')

You can also try this just to make sure:

sys.path.insert(0, 'C:\\Users\\%User%\\AppData\\Roaming\\McNeel\\Rhinoceros\\6.0\\scripts\\UWG')

A common mistake is to use append rather then insert, and not fix the order problem. If you are using insert, I think that should work… As long as you run that at the beginning of any Dragonfly session, it should force the IronPython editor to search the Rhino scripts directory first. It may not be good coding practice, because you are adding redundant paths, but it should work.

Let me know if you’ve tried that. Alternatively, print the sys.path before and after this is occurring, and we can at least confirm if path order is the cause of this problem.

Saeran

1 Like

Regarding question 2.

I remember now that the absence of the roof albedo and roof vegetation fractions are due to an earlier question we were having about the contribution of the roof parameters to the urban canyon.

Essentially, one of Joseph’s contribution to the UWG was to bound the volume of the urban canyon to the top of the building heights. and have the the Urban boundary layer extend vertically from the top of the representative building. (In the previous model the canyon height was twice the building height). In this way, all the heat from the roof is contributed to the boundary layer, and not the canyon layer. Arguably this underestimates the heat contribution from roofs to the urban canyon, but it made UWG more consistent with the Town Energy Balance model.

As such, originally we were going to remove the roof albedo, and roof vegetation fraction in inputs from the user inputs, since it was reasoned that it didn’t have an impact on the urban canyon. (Especially as the boundary layer didn’t take into account radiation from the roof). However, Joseph pointed out that the sensible heat flux from the roof to the boundary layer, which impacts the canyon conditions through advective exchange should be represented, so we kept those inputs.

Anyway, all of this is to say, I think in removing, then re-adding these inputs, it looks like the roof characteristics weren’t fully added back into the GH side of things. While it is true that the roof characteristics have less of an impact on the urban canyon then the wall surfaces in this model, I think we should be taking the area-weighted average of the different building typology roof characteristics during the merging process.

S

2 Likes

Thanks @SaeranVasanthakumar , for answering the majority of the questions. Especially the ones about the path, which seems pretty complex and I am at a bit of a loss to explain.

I can confirm that points 1. and 2. are bugs that we should fix. They are both relics from early points in the design of Dragonfly (as Saeran points out about the roof parameters). The _bldg_types is also a relic from when I was playing with a different way of linking the building typologies and the disctionary that stores the ratios of the typologies on the city object.

@annasong , you are welcome to send another pull request with fixes and I’ll metge it in (thank you again for the last one you sent!) Otherwise, I can take care of it in a day or two.

1 Like

@SaeranVasanthakumar,

Thanks so much for your explanation! I think you’re right, in that the Desktop\urbanWeatherGen-master UWG version was being imported because I was running other python files also residing in the urbanWeatherGen-master folder.

Because I often cannot replicate this issue of the incorrect UWG file being imported, I just now tried to import the incorrect UWG file (since DF is importing the correct version) to test my control of the import process. Below is an image of the code I added to the DF Run UWG component and the test results.

Unfortunately, the results show that while I’ve changed sys.path accordingly to begin with the Desktop location, the UWG version imported is still from the Rhino scripts folder. I also tried inserting this piece of code into the DF Dragonfly component with the same results. When the incorrect version was being imported, I also tried to insert to sys.path the Rhino scripts folder location in this way to no avail. I’m thinking Rhino might have its own paths that it searches through before it goes through sys.path.

Regardless, I think I understand now why the wrong import was happening. Thanks once again for your detailed explanation!

Also, thanks for your response to my second question! It all makes sense now.

@chris,

Thanks for the explanation! I created a pull request with proposed edits for these two issues. To calculate the new roof albedo and roof veg fraction for the merged typology, I averaged the old roof albedo and roof veg fractions by the footprint areas of the old typologies. As for the second issue, I deleted that line of code appending the program string to self._bldg._types, but I’m not sure if that’s the optimal solution you had in mind.

Thanks.

Thank you, @annasong ! I merged in your fixes. You’ve saved us from a lot of bugs that would have caused us some headaches down the line :slight_smile:

1 Like

I think I know why the sys.path insert() didn’t work. I forgot that the python package defines and loads all local modules in its package during it’s initialization in the init.py file. So the “UWG” variable in this case is already likely already attached to the scripts directory UWG right at the beginning, and changing the sys.path downstream won’t change that. I say “likely” because, I don’t know how GHPython initializes the python in it’s components, but I assume it’s working in a similar fashion.

So rather then printing your sys.path, print your globals(). globals() is a method in python that returns a dictionary of all the variables in your module. I believe in this case you should see that the ‘UWG’ key is attached the module path to your desktop UWG (or whatever the wrong path is).

Unfortunately I’m not sure how to fix this. Stackoverflow seems to suggest not start clearing or messing around with the globals() dictionary. Maybe you could just redefine the UWG key with the correct module path? Anyway, I hope this at least provides some more context on the problem, and I think posting on Stackoverflow would be the best way of resolving it.

1 Like

@SaeranVasanthakumar,

Yes, this really helps explain why changing sys.path didn’t affect the address from which UWG was being imported. Thank you so much for your insight and suggestions!

For what it’s worth, see this post by Giulio:

1 Like

@SaeranVasanthakumar and @annasong ,

I believe that I have found a solution, which I arrived at through a test I was doing that had nothing to do with the UWG. It seems that, if a folder containing python libraries is in the same directory as the grasshopper script that is importing those libraries, the grasshopper script will load the libraries from that folder instead of the Rhino scripts folder.

Based on this logic, I would venture a guess that the grasshopper script that you were working with @annasong is also on your desktop. If so, then we have found the solution, which is simply to move the uwg libraries into a different directory than your grasshopper script.

If not, then we may have to keep searching for the answer.

1 Like

I should also say that, if you ever want to purposefully load a python library from a given location, @mostapha 's response on this post is a good way to do it:

2 Likes

@chris and @SaeranVasanthakumar,

Thanks for looking into this issue, Chris! Just to clarify, when you refer to the “grasshopper script”, do you mean the script behind the Dragonfly components used in the Grasshopper Definition file (UWG Workflow)? If so, the source code for these components are located in the Dragonfly-master folder I downloaded from GitHub, and unfortunately they are not located in the Desktop folder.

Thanks again.

@chris and @SaeranVasanthakumar,

I think I’ve found a piece of code that will import the desired version of UWG that only uses Python libraries. It’s a slight modification off of the solution for Python 2 posted here: https://stackoverflow.com/questions/67631/how-to-import-a-module-given-the-full-path.

The code is:

import imp

filepath = "C:\\Users\\Anna Song\\AppData\\Roaming\\McNeel\\Rhinoceros\\6.0\\scripts\\UWG\\__init__.py"
#filepath = "C:\\Users\\Anna Song\\Desktop\\urbanWeatherGen-master\\UWG\\__init__.py"

foo = imp.load_source('all', filepath)
from all import UWG

Filepath is the path to the file we want to import, which in our case is the init.py file in the UWG folder provided in the Rhino 6 scripts folder (although we could choose to import the init.py in the Desktop UWG folder). I believe we should choose to import the init.py instead of UWG.py itself since UWG.py imports other files in the UWG folder, and so errors are raised if we just import UWG.py because the files it imports cannot be found.

The first argument to imp.load_source is the name we give the module that filepath leads us to. By importing init.py first, we can successfully import UWG from init.py (now named all).

Thank you for all of your help! The previous suggestions and solutions were really constructive!

Hi @SaeranVasanthakumar,

In response to one of my previous questions, we discussed how when typologies are merged via create_merged_typology, the roof_albedo and roof_veg_fraction parameter values of the individual typologies weren’t preserved in the new merged typology when their values were not the default values (in other words, they were user entered).

I’m wondering if the same applies to the shgc parameter? The shgc parameter value for the new merged typology doesn’t seem to take into account the shgc values of the original individual typologies.

In the case that at least one of the two shgc values was set by the user, should the other shgc value that’s equal to None be initialized to its default value (or both shgc values could have been set by the user) and the two resulting shgc values be averaged by façade area?

Thanks.

Sorry for the late response, but yes, the SHGC should definitely be area-weighted as well. I will take a look at the code when I have some time.

1 Like

@SaeranVasanthakumar,

Not late at all! Thanks!