2

In my simulation I have a particle class and a nbody class.

struct Particle{
    double m;           // mass
    double x[DIM];      // position
    double v[DIM];      // velocity
    double F[DIM];      // force 
    double F_old[DIM];  // force past time step
    void update_position(double dt);
    void update_velocity(double dt);
    void update_force(Particle*, Particle*);
};

class Nbody {
    private:
        const double dt;                // step size
        const double t_max;             // max simulation time
        std::vector<Particle> p;
    public:
        Nbody(unsigned int n_, double dt_, double t_max_);
        void comp_force();
        void comp_position();
        void comp_velocity();
};

I update the position of every particle by looping over every particle and calling void Particle::update_position().

void Nbody::comp_position() {
    for (Particle& particle: p) { 
        particle.update_position(dt);
    }
}

In the following code snippet, I show the update rule to compute the new position.

void Particle::update_position(double dt) {
    const double a = dt * 0.5 / m;
    for (unsigned int d=0; d<DIM; ++d) {
        x[d] += dt * (v[d] + a * F[d]);
        F_old[d] = F[d];
    }
}

However, I have problems with the force calculation where I want to compute the interaction of particles and therefore need a nested loop. How can I do that? Here is my approach so far, which gives me an error:

void Particle::update_force(Particle* i, Particle* j) {
    double r=EPS; // smoothing
    for (unsigned int d=0; d<DIM; d++) {
        r += sqr(j->x[d] - i->x[d]);
    }
    const double f = i->m * j->m / (sqrt(r) * r);
    for (unsigned int d=0; d<DIM; d++) {
        i->F[d] += f * (j->x[d] - i->x[d]);
        j->F[d] -= f * (j->x[d] - i->x[d]);
    }
}

void Nbody::comp_force() {
    for (Particle& particle: p) {
        for (unsigned int d=0; d<DIM; ++d) {
            particle.F[d] = 0.;
        }
    }
    for (unsigned int i=0; i<n; i++) {
        for (unsigned int j=i+1; j<n; j++) {
            update_force(&p[i], &p[j]);
        }
    }
}

Here is the error I get:

nbody.cpp: In member function ‘void Nbody::comp_force()’:
nbody.cpp:84:13: error: ‘update_force’ was not declared in this scope
             update_force(&p[i], &p[j]);
             ^~~~~~~~~~~~

Can I write this similar as the update_position method?

6
  • @uneven_mark Sorry, you are right. Will update my question. Commented Oct 25, 2019 at 16:30
  • Suggestion: Your position, velocity and force could all benefit from a vector class (not std::vector but a math vector). template <size_t Dim> class Vector {... Commented Oct 25, 2019 at 16:33
  • 2
    Particle::update_force is being called from Nbody::comp_force. Note the differing scopes. Commented Oct 25, 2019 at 16:38
  • 1
    Looks like Particle::update_force could be made static (or a friend free function, but static seems more appealing to me here). Commented Oct 25, 2019 at 16:41
  • @TedLyngmo Could you elaborate on your suggestion a little? I can't imagine how I could implement that. Commented Oct 25, 2019 at 17:33

1 Answer 1

3

You are calling update_force defined as a member function on a Particle from a member function of NBody. There is no function update_force in the scope of NBody, hence the error. My suggestion would be to not define update_force as a member function on a particle, but as a free function outside Particle:

struct Particle{
    double m;           // mass
    double x[DIM];      // position
    double v[DIM];      // velocity
    double F[DIM];      // force 
    double F_old[DIM];  // force past time step
    void update_position(double dt);
    void update_velocity(double dt);
};

...

void update_particle_force(Particle& i, Particle& j) {
    double r=EPS; // smoothing
    for (unsigned int d=0; d<DIM; d++) {
        r += sqr(j.x[d] - i.x[d]);
    }
    const double f = i.m * j.m / (sqrt(r) * r);
    for (unsigned int d=0; d<DIM; d++) {
        i.F[d] += f * (j.x[d] - i.x[d]);
        j.F[d] -= f * (j.x[d] - i.x[d]);
    }
}

which is then called as:

...
update_particle_force(p[i], p[j]);
...

The advantage of using references over pointers for the parameters of update_particle_force is that to a certain extent you will avoid null pointer dereferences; the potential burden of the null pointer check is now on the caller of update_particle_force.

Sign up to request clarification or add additional context in comments.

1 Comment

Huh. It didn't click that Particle was a struct That eliminates my objections to update_force being a free function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.