Finnur Pind
Finnur Pind

Reputation: 67

Matlab: associating an ID with a dataset (e.g. struct)?

I am developing a certain feature for a high-order finite element simulation algorithm in Matlab and I am wondering what is a good way of implementing a certain task. I believe I am facing a somewhat common problem, but after doing some digging, I'm not really finding a good solution.

Basically, I have a long list of ID's (corresponding to certain nodes on my mesh), where each ID is associated with small data set. Then when I am running my solver, I need to access the data associated with these nodes and update the data (multiple times).

So, for example, let's say that this is my list of these specific nodes:

nodelist = [3 27 38] %(so these are my node ID's) 

Then for each node I have the following dataset associated

a (scalar)
b (5x5 double matrix)
c (10x1 double vector)

(a total of 36 double values associated with each node ID)

In reality, I will of course have a much, much longer list of node ID's and a somewhat larger data set associated with each node (but still only double scalars, matrices and vectors (no characters, strings etc)).

Approach 1

So one approach I cooked up is just to store everything in a 2D double matrix, and then do some relatively complex indexing to access my data when needed. For the example above, the size of my 2D matrix would be

size(2Dmat) = [length(nodelist), 36]

Say I wanted to access b(3,3) for node ID 27, I would access 2Dmat(2,14).

In principle, this works, but the code is just not very clean and readable because of this complex indexing (not to mention, when I change something in the way the data set is set up, I need to re-adjust the whole indexing code).

Approach 2

Another approach would be to use some sort of struct for each node in the node list:

a = 4.4;
b = rand(5,5);
c = rand(10,1);
s = struct('a',a,'b',b,'c',c)

And then I can access the data via, e.g., s.b(3,3) etc. But I just don't know how to associate a struct with the node ID?

Approach 3

The last thing I could think of would be to set up some sort of SQL database, but this seems like an overkill. And besides, I need my code to be as fast as possible, since I need to access these fields in the datasets associated with these chosen nodes many, many times and I imagine doing some queries into a database will slow things down.

Note that ultimately I will convert the code from Matlab to C/C++, so I would prefer to implement something that doesn't rely to heavily on some Matlab specific features.

So, any thoughts on how to implement this functionality in a clean way? I hope my question makes sense and thanks in advance!

Upvotes: 2

Views: 156

Answers (2)

gnovice
gnovice

Reputation: 125874

I think the cleanest solution, given a non-contiguous set of node IDs, would be approach 2 making use of a map container where your node ID is the key (i.e. index) into the map. This can be implemented in MATLAB using a containers.Map object, and in C++ using the std::map container. For example, here's how you can create and add values to a node map in MATLAB:

>> nodeMap = containers.Map('KeyType', 'double', 'ValueType', 'any');
>> nodelist = [3 27 38];
>> nodeMap(nodelist(1)) = struct('a', 4.4, 'b', rand(5, 5), 'c', rand(10, 1));
>> nodeMap(3)

ans = 

  struct with fields:

    a: 4.400000000000000
    b: [5×5 double]
    c: [10×1 double]

>> nodeMap(3).b(3,3)

ans =

   0.646313010111265

In C++, you would need to define a structure or class (e.g. Node) for the data type to be stored in the map. Here's an example (... denotes arguments passed to the Node constructor):

#include <map>

class Node {...};   // Define Node class
typedef std::map<int, Node> NodeMap;  // Using int for key type

int main()
{
  NodeMap map1;

  map1[3] = Node(...);  // Initialize and assign Node object
  map1.emplace(27, std::forward_as_tuple<...>);  // Create Node object in-place
}

Upvotes: 2

Cris Luengo
Cris Luengo

Reputation: 60635

Approach 2 is the cleanest, and readily translates to C++. For each node you have a struct s, then:

data(nodeID) = s;

is what is called a struct array. You index as

data(id).b(3,3) = 0.0;

This assumes that the IDs are contiguous, or that there are no huge gaps in their values. But this can always be ensured, it is easy to renumber node IDs if necessary.


In C++, you’d have a vector of structs:

struct Bla{
   double a;
   double b[3][3];
   double c[10];
};

std::vector<Bla> data(N);

Or in C:

Bla* data = malloc(sizeof(Bla)*N);

(and don’t forget free(data) when you’re done with it).

Then, in either C or C++, you access an element this way:

data[id].b[2][2] = 0.0;

The translation is obvious, except that indexing starts at 0 in C++ and at 1 in MATLAB.


Note that this method has a larger memory overhead than Approach 1 in MATLAB, but not in C or C++.

Approach 3 is a bad idea, it will just slow down your code without any benefits.

Upvotes: 2

Related Questions