Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6130191
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 23, 20262026-05-23T16:49:45+00:00 2026-05-23T16:49:45+00:00

This question is about the best strategy for implementing the following simulation in C++.

  • 0

This question is about the best strategy for implementing the following simulation in C++.

I’m trying to make a simulation as a part of a physics research project, which basically tracks the dynamics of a chain of nodes in space. Each node contains a position together with certain parameters (local curvature, velocity, distance to neighbors etc…) which all evolve trough time.

Each time step can be broken down to these four parts:

  • Calculate local parameters. The values are dependent on the nearest neighbors in the chain.
  • Calculate global parameters.
  • Evolving. The position of each node is moved a small amount, depending on global and local parameters, and some random force fields.
  • Padding. New nodes are inserted if the distance between two consecutive nodes reach a critical value.

(In addition, nodes can get stuck, which make them inactive for the rest of the simulation. The local parameters of inactive nodes with inactive neighbors, will not change, and does not need any more calculation.)

Each node contains ~ 60 bytes, I have ~ 100 000 nodes in the chain, and i need to evolve the chain about ~ 1 000 000 time steps. I would however like to maximize these numbers, as it would increase the accuracy of my simulation, but under the restriction that the simulation is done in reasonable time (~hours). (~30 % of the nodes will be inactive.)

I have started to implement this simulation as a doubly linked list in C++. This seems natural, as I need to insert new nodes in between existing ones, and because the local parameters depends on the nearest neighbors. (I added an extra pointer to the next active node, to avoid unnecessary calculation, whenever I loop over the whole chain).

I’m no expert when it comes to parallelization (or coding for that matter), but I have played around with OpenMP, and I really like how I can speed up for loops of independent operations with two lines of code. I do not know how to make my linked list do stuff in parallel, or if it even works (?). So I had this idea of working with stl vector. Where Instead of having pointers to the nearest neighbors, I could store the indices of the neighbors and access them by standard lookup. I could also sort the vector by the position the chain (every x’th timestep) to get a better locality in memory. This approach would allowed for looping the OpenMP way.

I’m kind of intimidated by the idea, as I don’t have to deal with memory management. And I guess that the stl vector implementation is way better than my simple ‘new’ and ‘delete’ way of dealing with Nodes in the list. I know I could have done the same with stl lists, but i don’t like the way I have to access the nearest neighbors with iterators.

So I ask you, 1337 h4x0r and skilled programmers, what would be a better design for my simulation? Is the vector approach sketched above a good idea? Or are there tricks to play on linked list to make them work with OpenMP? Or should I consider a totally different approach?

The simulation is going to run on a computer with 8 cores and 48G RAM, so I guess I can trade a lot of memory for speed.

Thanks in advance

Edit:
I need to add 1-2 % new nodes each time step, so storing them as a vector without indices to nearest neighbors won’t work unless I sort the vector every time step.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-23T16:49:46+00:00Added an answer on May 23, 2026 at 4:49 pm

    This is a classic tradeoff question. Using an array or std::vector will make the calculations faster and the insertions slower; using a doubly linked list or std::list will make the insertions faster and the calculations slower.

    The only way to judge tradeoff questions is empirically; which will work faster for your particular application? All you can really do is try it both ways and see. The more intense the computation and the shorter the stencil (eg, the computational intensity — how many flops you have to do per amount of memory you have to bring in) the less important a standard array will be. But basically you should mock up an implementation of your basic computation both ways and see if it matters. I’ve hacked together a very crude go at something with both std::vector and std::list; it is probably wrong in any of a numer of ways, but you can give it a go and play with some of the parameters and see which wins for you. On my system for the sizes and amount of computation given, list is faster, but it can go either way pretty easily.

    W/rt openmp, yes, if that’s the way you’re going to go, you’re hands are somewhat tied; you’ll almost certainly have to go with the vector structure, but first you should make sure that the extra cost of the insertions won’t blow away any benifit of multiple cores.

    #include <iostream>
    #include <list>
    #include <vector>
    #include <cmath>
    #include <sys/time.h>
    using namespace std;
    
    struct node {
        bool stuck;
        double x[2];
        double loccurve;
        double disttoprev;
    };
    
    void tick(struct timeval *t) {
        gettimeofday(t, NULL);
    }
    
    /* returns time in seconds from now to time described by t */
    double tock(struct timeval *t) {
        struct timeval now;
        gettimeofday(&now, NULL);
        return (double)(now.tv_sec - t->tv_sec) +
            ((double)(now.tv_usec - t->tv_usec)/1000000.);
    }
    
    int main()
    {
        const int nstart = 100;
        const int niters = 100;
        const int nevery = 30;
        const bool doPrint = false;
        list<struct node>   nodelist;
        vector<struct node> nodevect;
    
        // Note - vector is *much* faster if you know ahead of time 
        //  maximum size of vector
        nodevect.reserve(nstart*30);
    
        // Initialize
        for (int i = 0; i < nstart; i++) {
            struct node *mynode = new struct node;
            mynode->stuck = false;
            mynode->x[0] = i; mynode->x[1] = 2.*i;
            mynode->loccurve = -1;
            mynode->disttoprev = -1;
    
            nodelist.push_back( *mynode );
            nodevect.push_back( *mynode );
        }
    
        const double EPSILON = 1.e-6;
        struct timeval listclock;
        double listtime;
    
        tick(&listclock);
        for (int i=0; i<niters; i++) {
            // Calculate local curvature, distance
    
            list<struct node>::iterator prev, next, cur;
            double dx1, dx2, dy1, dy2;
    
            next = cur = prev = nodelist.begin();
            cur++;
            next++; next++;
            dx1 = prev->x[0]-cur->x[0];
            dy1 = prev->x[1]-cur->x[1];
    
            while (next != nodelist.end()) {
                dx2 = cur->x[0]-next->x[0];
                dy2 = cur->x[1]-next->x[1];
    
                double slope1 = (dy1/(dx1+EPSILON));
                double slope2 = (dy2/(dx2+EPSILON));
    
                cur->disttoprev = sqrt(dx1*dx1 + dx2*dx2 );
    
                cur->loccurve = ( slope1*slope2*(dy1+dy2) +
                                  slope2*(prev->x[0]+cur->x[0]) -
                                  slope1*(cur->x[0] +next->x[0]) ) /
                                (2.*(slope2-slope1) + EPSILON);
    
                next++;
                cur++;
                prev++;
            }
    
            // Insert interpolated pt every neveryth pt
            int count = 1;
            next = cur = nodelist.begin();
            next++;
            while (next != nodelist.end()) {
                if (count % nevery == 0) {
                    struct node *mynode = new struct node;
                    mynode->x[0] = (cur->x[0]+next->x[0])/2.;
                    mynode->x[1] = (cur->x[1]+next->x[1])/2.;
                    mynode->stuck = false;
                    mynode->loccurve = -1;
                    mynode->disttoprev = -1;
                    nodelist.insert(next,*mynode);
                }
                next++;
                cur++;
                count++;
            }
        }
                                                                   51,0-1        40%
    
        struct timeval vectclock;
        double vecttime;
    
        tick(&vectclock);
        for (int i=0; i<niters; i++) {
            int nelem = nodevect.size();
            double dx1, dy1, dx2, dy2;
            dx1 = nodevect[0].x[0]-nodevect[1].x[0];
            dy1 = nodevect[0].x[1]-nodevect[1].x[1];
    
            for (int elem=1; elem<nelem-1; elem++) {
                dx2 = nodevect[elem].x[0]-nodevect[elem+1].x[0];
                dy2 = nodevect[elem].x[1]-nodevect[elem+1].x[1];
    
                double slope1 = (dy1/(dx1+EPSILON));
                double slope2 = (dy2/(dx2+EPSILON));
    
                nodevect[elem].disttoprev = sqrt(dx1*dx1 + dx2*dx2 );
    
                nodevect[elem].loccurve = ( slope1*slope2*(dy1+dy2) +
                                  slope2*(nodevect[elem-1].x[0] +
                                          nodevect[elem].x[0])  -
                                  slope1*(nodevect[elem].x[0] +
                                          nodevect[elem+1].x[0]) ) /
                                (2.*(slope2-slope1) + EPSILON);
    
            }
    
            // Insert interpolated pt every neveryth pt
            int count = 1;
            vector<struct node>::iterator next, cur;
            next = cur = nodevect.begin();
            next++;
            while (next != nodevect.end()) {
                if (count % nevery == 0) {
                    struct node *mynode = new struct node;
                    mynode->x[0] = (cur->x[0]+next->x[0])/2.;
                    mynode->x[1] = (cur->x[1]+next->x[1])/2.;
                    mynode->stuck = false;
                    mynode->loccurve = -1;
                    mynode->disttoprev = -1;
                    nodevect.insert(next,*mynode);
                }
                next++;
                cur++;
                count++;
            }
        }
        vecttime = tock(&vectclock);
    
        cout << "Time for list: " << listtime << endl;
        cout << "Time for vect: " << vecttime << endl;
    
        vector<struct node>::iterator v;
        list  <struct node>::iterator l;
    
        if (doPrint) {
            cout << "Vector: " << endl;
            for (v=nodevect.begin(); v!=nodevect.end(); ++v) {
                 cout << "[ (" << v->x[0] << "," << v->x[1] << "), " << v->disttoprev << ", " << v->loccurve << "] " << endl;
            }
    
            cout << endl << "List: " << endl;
            for (l=nodelist.begin(); l!=nodelist.end(); ++l) {
                 cout << "[ (" << l->x[0] << "," << l->x[1] << "), " << l->disttoprev << ", " << l->loccurve << "] " << endl;
            }
    
        }
    
        cout << "List size is " << nodelist.size() << endl;
    }
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

This question is not about which is the best, it is about which makes
this question is about best practices. I'm implementing a 3D interval Kd-Tree and, because
I have this question about best practices in following examples: interface Request; interface Service
This question is about best use scenarios in projects with ORMs like NHibernate, Subsonic,
This question is not about 'best' barcode library recommendation, we use various products on
You can read this question where I ask about the best architecture for a
This may be a question about convention, best practices and/or personal preferences: So I'm
I know this is a subjective question, but I'm always curious about best-practices in
This question arose when I was working on answering another question about best practices
(This question is about the best way to temporarily and programatically keep new records

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.