LB Deconstruct Data: output wrapping

There is a rather simple way to speed up the LB Deconstruct Data component by wrapping the output values in GH_Number objects:

from Grasshopper.Kernel.Types import GH_Number
...
    values = [GH_Number(v) for v in _data.values]

Here is an example of the speedup for extracting hourly data from 19 zones in an energy simulation (top is original component, bottom is with the above changes):

The reason for the speedup is that Grasshopper does a lot of checking to determine what type of object is being passed, on an item-by-item basis, so it can wrap them in the appropriate GH_ objects. By explicitly doing the wrapping ourselves, Grasshopper does not need to do the slow checking step. The wrapping is mostly helpful for components passing around thousands of objects, which is often the case with the LB Deconstruct Data component.

Any chance this change can get added to the Ladybug component?

Full Component Code
# Ladybug: A Plugin for Environmental Analysis (GPL)
# This file is part of Ladybug.
#
# Copyright (c) 2024, Ladybug Tools.
# You should have received a copy of the GNU Affero General Public License
# along with Ladybug; If not, see <http://www.gnu.org/licenses/>.
# 
# @license AGPL-3.0-or-later <https://spdx.org/licenses/AGPL-3.0-or-later>

"""
Deconstruct a Ladybug DataCollection into a header and values.
-

    Args:
        _data: A Ladybug DataCollection object.
    Returns:
        header: The header of the DataCollection (containing metadata).
        values: The numerical values of the DataCollection.
"""

ghenv.Component.Name = "LB Deconstruct Data"
ghenv.Component.NickName = 'XData'
ghenv.Component.Message = '1.8.0'
ghenv.Component.Category = 'Ladybug'
ghenv.Component.SubCategory = '1 :: Analyze Data'
ghenv.Component.AdditionalHelpFromDocStrings = '1'

from Grasshopper.Kernel.Types import GH_Number

try:
    from ladybug.datacollection import BaseCollection
except ImportError as e:
    raise ImportError('\nFailed to import ladybug:\n\t{}'.format(e))

try:
    from ladybug_rhino.grasshopper import all_required_inputs
except ImportError as e:
    raise ImportError('\nFailed to import ladybug_rhino:\n\t{}'.format(e))


if all_required_inputs(ghenv.Component):
    assert isinstance(_data, BaseCollection), \
        '_data must be a Data Collection. Got {}.'.format(type(_data))
    header = _data.header
    values = [GH_Number(v) for v in _data.values]
4 Likes

Hi @savage,

Let’s wait for @chris and see what he thinks but unless the gain is substantial I would suggest not using Grasshopper-specific modules in the components. If we decide to do so, they should probably live in the ladybug-rhino module so other packages like ladybug-blender can overwrite them in the respective module.

Hi @mostapha,

The speed improvement probably doesn’t matter for simple models, but if working directly with 8760 data outside of LBT components on more complicated models, the extra time can add up. This change shaved 5-10 seconds off of the post-processing for the building I am currently working on, and I am running dozens of simulations.

Do the grasshopper and blender components share code? I was having a little trouble finding what Github repo the python embedded in the Grasshopper components is coming from. I assumed it was purely in the ladybug-grasshopper component, but your response is making me second-guess that. Do you have some sort of build process for the ghuser objects, and is it documented somewhere?