Utility functions

Asset directories

helios searches for assets in so-called asset directories. By default, these are

  • the helios installation directory

  • the data folder in the helios installation directory (containing the built-in scanners and platforms)

  • the current working directory

[1]:
import helios

We can add asset directories using the add_asset_directory function, and we can check which asset directories are currently registered using the get_asset_directories function.

[2]:
helios.utils.add_asset_directory("D:/Software/_helios_data/urban")
[3]:
helios.utils.get_asset_directories()
[3]:
[WindowsPath('D:/Software/_helios_data/urban'),
 WindowsPath('d:/Software/_helios_versions/helios/doc'),
 WindowsPath('D:/Software/_helios_versions/helios/python/helios'),
 WindowsPath('D:/Software/_helios_versions/helios/python/helios/data')]

Setting a random seed

To control the randomness in helios and make results reproducible, we can set the seed of the random number generator. The seed can be an integer number or a string timestamp with format “YYYY-MM-DD hh:mm:ss”.

[4]:
helios.utils.set_rng_seed(42)
helios.utils.set_rng_seed("2026-03-12 18:00:00")

If the user does not specify a seed, then the seed is randomly computed. Despite controlling the seed for random numbers, the concurrent nature of the simulation still generates output with no guaranteed order. By limiting the number of jobs to 1, the order is guaranteed and the output should be exactly the same for different executions. The number of jobs can be specified using the num_threads parameter of the ExecutionSettings.

Combinations of parameter settings

One of the most common use cases of helios is to repeat a survey with different parameter settings, e.g., to assess the sensitivity of an algorithm to different input point clouds or to find the best parameter settings to replicate a real-world survey. To facilitate this, helios provides the combine_parameters utility function. This function takes lists of possible parameters and allows combining them in complex ways to generate a list of parameter dictionaries. We are demonstrating a few examples below.

Option 1: Cartesian product

Let’ say we want to fine tune the full waveform parameters of our simulation. We want to test different bin sizes, window sizes, and beam sample qualities. We can define lists of possible values for each of these parameters and then use the combine_parameters function to generate the cartesian product of all possible combinations of these parameters:

[5]:
bin_sizes = [0.05, 0.1, 0.2, 0.25, 0.3]
win_sizes = [0.5, 1.0, 1.5, 2.0, 2.5]
bsqs = [3, 5]

params = helios.combine_parameters(
    bin_size=bin_sizes, win_size=win_sizes, beam_sample_quality=bsqs
)
params
[5]:
[{'bin_size': 0.05, 'win_size': 0.5, 'beam_sample_quality': 3},
 {'bin_size': 0.05, 'win_size': 0.5, 'beam_sample_quality': 5},
 {'bin_size': 0.05, 'win_size': 1.0, 'beam_sample_quality': 3},
 {'bin_size': 0.05, 'win_size': 1.0, 'beam_sample_quality': 5},
 {'bin_size': 0.05, 'win_size': 1.5, 'beam_sample_quality': 3},
 {'bin_size': 0.05, 'win_size': 1.5, 'beam_sample_quality': 5},
 {'bin_size': 0.05, 'win_size': 2.0, 'beam_sample_quality': 3},
 {'bin_size': 0.05, 'win_size': 2.0, 'beam_sample_quality': 5},
 {'bin_size': 0.05, 'win_size': 2.5, 'beam_sample_quality': 3},
 {'bin_size': 0.05, 'win_size': 2.5, 'beam_sample_quality': 5},
 {'bin_size': 0.1, 'win_size': 0.5, 'beam_sample_quality': 3},
 {'bin_size': 0.1, 'win_size': 0.5, 'beam_sample_quality': 5},
 {'bin_size': 0.1, 'win_size': 1.0, 'beam_sample_quality': 3},
 {'bin_size': 0.1, 'win_size': 1.0, 'beam_sample_quality': 5},
 {'bin_size': 0.1, 'win_size': 1.5, 'beam_sample_quality': 3},
 {'bin_size': 0.1, 'win_size': 1.5, 'beam_sample_quality': 5},
 {'bin_size': 0.1, 'win_size': 2.0, 'beam_sample_quality': 3},
 {'bin_size': 0.1, 'win_size': 2.0, 'beam_sample_quality': 5},
 {'bin_size': 0.1, 'win_size': 2.5, 'beam_sample_quality': 3},
 {'bin_size': 0.1, 'win_size': 2.5, 'beam_sample_quality': 5},
 {'bin_size': 0.2, 'win_size': 0.5, 'beam_sample_quality': 3},
 {'bin_size': 0.2, 'win_size': 0.5, 'beam_sample_quality': 5},
 {'bin_size': 0.2, 'win_size': 1.0, 'beam_sample_quality': 3},
 {'bin_size': 0.2, 'win_size': 1.0, 'beam_sample_quality': 5},
 {'bin_size': 0.2, 'win_size': 1.5, 'beam_sample_quality': 3},
 {'bin_size': 0.2, 'win_size': 1.5, 'beam_sample_quality': 5},
 {'bin_size': 0.2, 'win_size': 2.0, 'beam_sample_quality': 3},
 {'bin_size': 0.2, 'win_size': 2.0, 'beam_sample_quality': 5},
 {'bin_size': 0.2, 'win_size': 2.5, 'beam_sample_quality': 3},
 {'bin_size': 0.2, 'win_size': 2.5, 'beam_sample_quality': 5},
 {'bin_size': 0.25, 'win_size': 0.5, 'beam_sample_quality': 3},
 {'bin_size': 0.25, 'win_size': 0.5, 'beam_sample_quality': 5},
 {'bin_size': 0.25, 'win_size': 1.0, 'beam_sample_quality': 3},
 {'bin_size': 0.25, 'win_size': 1.0, 'beam_sample_quality': 5},
 {'bin_size': 0.25, 'win_size': 1.5, 'beam_sample_quality': 3},
 {'bin_size': 0.25, 'win_size': 1.5, 'beam_sample_quality': 5},
 {'bin_size': 0.25, 'win_size': 2.0, 'beam_sample_quality': 3},
 {'bin_size': 0.25, 'win_size': 2.0, 'beam_sample_quality': 5},
 {'bin_size': 0.25, 'win_size': 2.5, 'beam_sample_quality': 3},
 {'bin_size': 0.25, 'win_size': 2.5, 'beam_sample_quality': 5},
 {'bin_size': 0.3, 'win_size': 0.5, 'beam_sample_quality': 3},
 {'bin_size': 0.3, 'win_size': 0.5, 'beam_sample_quality': 5},
 {'bin_size': 0.3, 'win_size': 1.0, 'beam_sample_quality': 3},
 {'bin_size': 0.3, 'win_size': 1.0, 'beam_sample_quality': 5},
 {'bin_size': 0.3, 'win_size': 1.5, 'beam_sample_quality': 3},
 {'bin_size': 0.3, 'win_size': 1.5, 'beam_sample_quality': 5},
 {'bin_size': 0.3, 'win_size': 2.0, 'beam_sample_quality': 3},
 {'bin_size': 0.3, 'win_size': 2.0, 'beam_sample_quality': 5},
 {'bin_size': 0.3, 'win_size': 2.5, 'beam_sample_quality': 3},
 {'bin_size': 0.3, 'win_size': 2.5, 'beam_sample_quality': 5}]

We could directly iterate over all the combinations and run surveys accordingly:

# load scene, define scan settings
for params in helios.combine_parameters(bin_size=bin_sizes, win_size=win_sizes, beam_sample_quality=bsqs):

    scanner_tls = helios.scanner_from_name("riegl_vz_400")
    platform_tls = helios.platform_from_name("tripod")

    # Full waveform settings
    fullwave_settings = helios.FullWaveformSettings(
        bin_size=params["bin_size"] * helios.units.ns,
        beam_sample_quality=params["beam_sample_quality"],
        win_size=params["win_size"] * helios.units.ns
    )

    survey_tls = helios.Survey(scanner=scanner_tls, platform=platform_tls, scene=scene, full_waveform_settings=fullwave_settings)
    # add legs, run survey, ..

Option 2: Zip

As a second option, we can also zip two ranges. For this, we have to provide the groups parameter.

[6]:
for params in helios.combine_parameters(
    x=[-5, -5, 5, 5], y=[-10, 10, 10, -10], z=[30, 30, 30, 30], groups=[["x", "y", "z"]]
):
    print(params)
{'x': -5, 'y': -10, 'z': 30}
{'x': -5, 'y': 10, 'z': 30}
{'x': 5, 'y': 10, 'z': 30}
{'x': 5, 'y': -10, 'z': 30}

Option 3: Combining cartesian product and zip

[7]:
for params in helios.combine_parameters(
    x=[0, 1], y=[0, 1], z=[10, 20], groups=[["x", "y"], ["z"]]
):
    print(params)
{'x': 0, 'y': 0, 'z': 10}
{'x': 0, 'y': 0, 'z': 20}
{'x': 1, 'y': 1, 'z': 10}
{'x': 1, 'y': 1, 'z': 20}

The function even allows us to define string parameters that use Python format string expressions. They will be formatted against the expanded parameters:

[8]:
for params in helios.combine_parameters(x=[0, 1], coordinate="x={x}"):
    print(params)
{'coordinate': 'x=0', 'x': 0}
{'coordinate': 'x=1', 'x': 1}