Back

Manager

Overview

The df::attributes::Manager class orchestrates attribute decomposition by managing multiple Decomposer instances and providing unified access to decomposed attributes. It allows you to break down complex data types (vectors, matrices, tensors) into their individual components for analysis and visualization.

Include
#include <dataframe/attributes/Manager.h>

DecompDimension Enum

Controls the level of decomposition when querying attribute names or extracting components.

DecompDimension
namespace df::attributes {

enum class DecompDimension {
    Scalar = 1,  // Individual components (x, y, z, xx, xy, ...)
    Vector,      // N-dimensional vectors
    Matrix       // N-dimensional matrices/tensors
};

}
ValueDescription
ScalarDecompose into individual scalar components
VectorDecompose into vector-level groups
MatrixDecompose into matrix-level groups

Manager Class

Manager API
namespace df::attributes {

class Manager {
public:
    // Construct with a reference to a Dataframe
    explicit Manager(const Dataframe& df);

    // Copy constructor (deep-copies all decomposers)
    Manager(const Manager& other);

    // Add a decomposer to the manager
    void addDecomposer(const Decomposer& decomposer);

    // Get all decomposed attribute names for a given dimension
    std::vector<std::string> getNames(DecompDimension targetDim) const;

    // Get a decomposed attribute as Serie<T>
    template <typename T>
    Serie<T> getSerie(const std::string& name) const;

    // Check if an attribute exists
    bool hasAttribute(DecompDimension targetDim, const std::string& name) const;

    // Clear all registered decomposers
    void clear();

    // Get the number of registered decomposers
    size_t decomposerCount() const;
};

}

Basic Usage

Creating and Using a Manager
#include <dataframe/Serie.h>
#include <dataframe/algebra/types.h>
#include <dataframe/attributes/Manager.h>
#include <dataframe/attributes/Components.h>
#include <dataframe/attributes/Coordinates.h>

using namespace df;

// Create data
Serie<Vector3D> positions = {{1,0,0}, {0,1,0}, {0,0,1}};
Serie<Stress3D> stresses = {
    {1, 2, 3, 4, 5, 6},
    {7, 8, 9, 10, 11, 12}
};

// Build a Dataframe
Dataframe dataframe;
dataframe.add("P", positions);
dataframe.add("S", stresses);

// Create a Manager and register decomposers
attributes::Manager manager(dataframe);
manager.addDecomposer(attributes::Components());
manager.addDecomposer(attributes::Coordinates());

// Query available scalar names
auto names = manager.getNames(attributes::DecompDimension::Scalar);
// -> "Px", "Py", "Pz", "Sxx", "Sxy", "Sxz", "Syy", "Syz", "Szz",
//    "P_x", "P_y", "P_z"

// Extract a specific component
auto px = manager.getSerie<double>("Px");    // Position X via Components
auto sxx = manager.getSerie<double>("Sxx");  // Stress XX component

Querying by Dimension

Decomposition at Different Levels
// Scalar-level: individual components
auto scalars = manager.getNames(attributes::DecompDimension::Scalar);
// For Vector3D "P": Px, Py, Pz
// For Stress3D "S": Sxx, Sxy, Sxz, Syy, Syz, Szz

// Vector-level: grouped as vectors
auto vectors = manager.getNames(attributes::DecompDimension::Vector);
// -> "P", "S"

// Matrix-level: grouped as matrices/tensors
auto matrices = manager.getNames(attributes::DecompDimension::Matrix);
// -> "S" (only matrix/tensor types)

// Check if a specific attribute exists
if (manager.hasAttribute(attributes::DecompDimension::Scalar, "Sxy")) {
    auto sxy = manager.getSerie<double>("Sxy");
}

Complete Example

Full Workflow
#include <dataframe/Serie.h>
#include <dataframe/algebra/types.h>
#include <dataframe/attributes/Components.h>
#include <dataframe/attributes/Coordinates.h>
#include <dataframe/attributes/Manager.h>
#include <iostream>

using namespace df;

int main() {
    // Create sample data
    Serie<Vector3D> positions = {{1,0,0}, {0,1,0}, {0,0,1}};
    Serie<Stress3D> stresses = {
        {1, 2, 3, 4, 5, 6},
        {7, 8, 9, 10, 11, 12}
    };
    Serie<Matrix4D> tensors = {
        {1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16},
        {1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16}
    };

    // Build dataframe
    Dataframe dataframe;
    dataframe.add("P", positions);
    dataframe.add("S", stresses);
    dataframe.add("T", tensors);

    // Create manager and register decomposers
    attributes::Manager manager(dataframe);
    manager.addDecomposer(attributes::Components());

    // List all scalar names
    std::cout << "Scalar attributes:\n";
    for (const auto& name : manager.getNames(
             attributes::DecompDimension::Scalar)) {
        std::cout << "  " << name << "\n";
    }
    // Output:
    //   Px, Py, Pz
    //   Sxx, Sxy, Sxz, Syy, Syz, Szz
    //   T11, T12, T13, T14, T21, ..., T44

    // Extract and use components
    auto px = manager.getSerie<double>("Px");
    auto sxx = manager.getSerie<double>("Sxx");
    auto t12 = manager.getSerie<double>("T12");

    std::cout << "\nPosition X: ";
    for (size_t i = 0; i < px.size(); ++i) {
        std::cout << px[i] << " ";
    }
    // Output: 1 0 0

    std::cout << "\nStress XX: ";
    for (size_t i = 0; i < sxx.size(); ++i) {
        std::cout << sxx[i] << " ";
    }
    // Output: 1 7

    return 0;
}