Attributes#
Both Places and Agents can have a set of attributes attached. However, we cannot do that by adding member variables directly into the Place and Agent class since that will result in severe performance degradation due to uncoalesced memory access. As a result, special APIs are provided for defining and accessing attributes.
Define Attributes#
The setAttribute function is used to define attributes, which takes in a template type argument for the type of that attribute, and together with 4 normal arguments:
tag: An integer tag for identifying the attributeelementCount: Number of elements for the attribute. Value larger than 1 mean that this is a 2D attribute (array attribute). Value should not be smaller than 1.initialValue: The initial value of the attribute, should have the same type as the template type argument provided. This argument is optional, but it is recommended to provide it, otherwise it will be uninitialed random bytes.
For Places, there is one additional parameter permernentlyExcludedFromSyncBorder, which is a boolean showing whether this attribute should be permanently excluded during syncPlaceBorder call. This argument is optional with default value of false. It is mainly designed for internal uses and is usually not necessary to be modified. Only set it to true when you are 100% sure what you are doing.
Normally, before actually creating the attributes, it is recommended to define the tags of all the required attributes as an enum in the custom Place or Agent class.
class MyPlace final : public mass::Place {
public:
__universal__ explicit MyPlace(const mass::Index localIndex) : mass::Place(localIndex) {}
enum Attribute {
INT_ATTR,
DOUBLE_ATTR,
FLOAT_ARR_ATTR
};
__device__ void callMethod(const mass::FunctionId functionId, void*const args) {
// ...
}
// Other member methods...
};
Then, we can define the attributes through the created Places or Agents instance with the tags defined in the enum. After all the attributes being defined, call finalizeAttributes to commit the definition.
const auto places = mass::Mass::createPlaces<MyPlace>(/* ... */);
// an int attribute with inital value 0
places->setAttribute<int>(MyPlace::Attribute::INT_ATTR, 1, 0);
// a double attribute with no initial value
places->setAttribute<double>(MyPlace::Attribute::DOUBLE_ATTR, 1);
// a float 2D attribute (array attribute) with length of 4
// and inital value 2.0f for each element.
places->setAttribute<float>(MyPlace::Attribute::FLOAT_ARR_ATTR, 4, 2.0f);
places->finalizeAttributes();
Access Attributes#
Once the attributes are defined with setAttribute and committed with finalizeAttributes, they are ready to be accessed within member methods of the custom Place or Agent class. To access the value of an attribute, use the getAttribute and getArrAttribute methods, where both of them takes in the type of the attribute as a template argument and the tag of the attribute as a normal argument.
The return values of these two methods are pointer-like types pointing to the attribute value, and we can access the value using * or -> operator. For getAttribute, it is designed for 1D attributes (non-array attributes) whose value is a single value, so the return type does not implement the subscript operator []. On the contrary, getArrAttribute is designed for 2D attributes (array attributes), so the return type implements the subscript operator [] for accessing each element.
Continue with the MyPlace class above, we can add a member method and access the attributes as follows.
class MyPlace final : public mass::Place {
public:
__universal__ explicit MyPlace(const mass::Index localIndex) : mass::Place(localIndex) {}
enum Attribute {
INT_ATTR,
DOUBLE_ATTR,
FLOAT_ARR_ATTR
};
enum Function {
FUNC1
}
__device__ void callMethod(const mass::FunctionId functionId, void*const args) {
switch (functionId) {
case FUNC1: func1(); break;
default: break;
}
}
__device__ void func1() {
// get pointers to the attributes
const auto intAttr = getAttribute<int>(Attribute::INT_ATTR);
const auto doubleAttr = getAttribute<double>(Attribute::DOUBLE_ATTR);
const auto floatArrAttr = getArrAttribute<float>(Attribute::FLOAT_ARR_ATTR);
// read attribute values and do some computation
const auto v = *intAttr + *doubleAttr * 2;
for (int i = 0; i < 4; i++) {
// read & write to 2D attribute
floatArrAttr[i] += static_cast<float>(v + i);
}
}
};
Pre-Defined Attributes#
Besides the custom attributes we defined during simulations, MASS CUDA also provides some pre-defined attributes for both Place and Agent. The value of these attributes can be accessed through provided getters in Place and Agent classes.
For Place, the following pre-defined attributes are provided:
Getter |
Description |
|---|---|
|
get the flattened global index of the current |
|
get the flattened index of the current |
|
get the flattened index of the current block |
|
get the total number of |
|
get array of pointers to all the neighboring instances of the current |
|
get the array of pointers to all the |
|
get the number of |
|
get the array of |
|
get the number of |
For Agent, the following pre-defined attributes are provided:
Getter |
Description |
|---|---|
|
get the unique ID of the current |
|
get the flattened index of the current |
|
Same as |
|
get pointer to the |
|
get the flattened index of the |