Tutorial 5 - Array Data Node

Array data consists of multiple elements of a simple type whose count is only known at runtime. For example float[] or double[]. This node takes an array of floats and a multiplier and generates an output array consisting of the product of the two.

OgnTutorialArrayData.ogn

The ogn file shows the implementation of a node named “omni.graph.tutorials.ArrayData”, which has a float value and float array input with one float array output.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
{
    "ArrayData": {
        "version": 1,
        "categories": "tutorials",
        "description": ["This is a tutorial node. It will compute the array 'result' as the input array 'original' ",
                        "with every element multiplied by the constant 'multiplier'."
        ],
        "$todo": "Enable the string attributes when flatcache fully supports them",
        "metadata":
        {
           "uiName": "Tutorial Node: Array Attributes"

        },
        "inputs": {
            "original": {
                "description": "Array to be multiplied",
                "type": "float[]",
                "default": []
            },
            "gates": {
                "description": "Boolean mask telling which elements of the array should be multiplied",
                "type": "bool[]",
                "default": []
            },
            "multiplier": {
                "description": "Multiplier of the array elements",
                "type": "float",
                "default": 1.0
            },
            "info": {
                "description": "List of strings providing commentary",
                "type": "token[]",
                "default": ["There", "is", "no", "data"]
            }
        },
        "outputs": {
            "result": {
                "description": "Multiplied array",
                "type": "float[]"
            },
            "negativeValues": {
                "description": "Array of booleans set to true if the corresponding 'result' is negative",
                "type": "bool[]"
            },
            "infoSize": {
                "description": "Number of letters in all strings in the info input",
                "type": "int"
            }
        },
        "tests": [
            {
                "inputs:original": [1.0, 2.0, 3.0],
                "inputs:gates": [true, false, true],
                "inputs:multiplier": 2.0,
                "outputs:result": [2.0, 2.0, 6.0],
                "outputs:negativeValues": [false, false, false],
                "outputs:infoSize": 13
            },
            {
                "inputs:original": [10.0, -20.0, 30.0],
                "inputs:gates": [true, false, true],
                "outputs:result": [10.0, -20.0, 30.0],
                "outputs:negativeValues": [false, true, false]
            },
            {
                "inputs:info": ["Hello", "lamp\"post", "what'cha", "knowing"],
                "outputs:infoSize": 29
            }
        ]
    }
}

OgnTutorialArrayData.cpp

The cpp file contains the implementation of the compute method, which multiplies the float value by each member of the float array.

Note how the attribute Array values can be accessed as though they were a simple std::vector type.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto.  Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//
#include <OgnTutorialArrayDataDatabase.h>
#include <algorithm>

class OgnTutorialArrayData
{
public:
    static bool compute(OgnTutorialArrayDataDatabase& db)
    {
        // For clarity get the attribute values into separate variables. The type definitions are included to
        // show exactly what data types are returned, though you should know that from your .ogn declaration.
        // It's sufficient to use "const auto" for inputs or "auto" for outputs.
        const float multiplier = db.inputs.multiplier();
        const ::ogn::const_array<float>& inputArray = db.inputs.original();
        const ::ogn::const_array<bool>& gateArray = db.inputs.gates();
        ::ogn::array<float>& outputArray = db.outputs.result();
        ::ogn::array<bool>& negativeValues = db.outputs.negativeValues();

        if (gateArray.size() != inputArray.size())
        {
            db.logWarning("Gate array size %zu should equal input array size %zu", gateArray.size(), inputArray.size());
            return false;
        }

        // Output array data has to be properly sized before filling as it will contain the same number
        // of elements as the input the size is already known. You could also do an assignment and modify the
        // output in place if that makes your algorithm more efficient:
        //     outputArray = inputArray;
        outputArray.resize(inputArray.size());
        negativeValues.resize(inputArray.size());

        // The attribute array data wrapper is compatible with the STL algorithms so computations can be
        // performed in a single std::algorithm call.
        std::transform(inputArray.begin(), inputArray.end(), gateArray.begin(), outputArray.begin(),
                       [multiplier](const float& value, const bool& gate) -> float
                       { return gate ? value * multiplier : value; });
        std::transform(outputArray.begin(), outputArray.end(), negativeValues.begin(),
                        [](const float& value) -> bool { return value < 0.0f; });

        // Regular iterators can also be applied
        int totalCharacters{ 0 };
        for (const auto& stringInput : db.inputs.info())
        {
            totalCharacters += int(std::strlen(db.tokenToString(stringInput)));
        }
        db.outputs.infoSize() = totalCharacters;
        return true;
    }
};

REGISTER_OGN_NODE()

Array Attribute Access

The attribute access is as described in Tutorial 2 - Simple Data Node except that the exact return types of the attributes are different in order to support array member access.

Full definition of the array wrapper classes can be found in the interface file omni/graph/core/ogn/array.h, though they do behave in a manner consistent with std::array, supporting iterators, standard algorithms, random access through either operator[] or the at(index) function, the empty() and size() functions, and access to the raw underlying data using the function data(). The non-const version also supports assignment and the resize() function for modifying its contents.

Database Function

Returned Type

inputs.original()

const ogn::const_array<float>&

inputs.multiplier()

const float&

outputs.result()

ogn::array<float>&

These wrapper classes are similar in concept to std::span, which handles unmanaged pointer+size data. In this case the data is being managed by the FlatCache. Modifications to the wrapper class data will directly modify the underlying data in the FlatCache.

You can still use the auto declarations on these types, and the array attributes have an additional size() method added for convenience.

bool compute(OgnTutorialArrayDataDatabase& db)
{
    const auto& multiplier = db.inputs.multiplier();
    const auto& original = db.inputs.original();
    size_t originalSize = db.inputs.original.size();
    auto& result = db.outputs.result();
};