-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSimulation.h
More file actions
91 lines (78 loc) · 2.64 KB
/
Copy pathSimulation.h
File metadata and controls
91 lines (78 loc) · 2.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// Simulation.h
#pragma once
#include "Particle.h"
#include "GravityModel.h"
#include <vector>
#include <memory>
#include <stdexcept>
#include <omp.h>
class Simulation {
public:
std::vector<Particle> particles;
std::shared_ptr<GravityModel> gravityModel;
explicit Simulation(std::shared_ptr<GravityModel> model)
: gravityModel(std::move(model)) {
if (!gravityModel)
throw std::runtime_error("GravityModel must not be null");
}
void addParticle(const Particle& p) { particles.push_back(p); }
void step(double dt) {
computeForces();
for (auto& p : particles) {
p.vel += (1.0 / p.mass) * p.force * (dt * 0.5);
p.pos += p.vel * dt;
}
computeForces();
for (auto& p : particles) {
p.vel += (1.0 / p.mass) * p.force * (dt * 0.5);
}
}
double kineticEnergy() const {
double ke = 0;
for (const auto& p : particles) ke += p.kineticEnergy();
return ke;
}
double potentialEnergy() const {
double pe = 0;
for (size_t i = 0; i < particles.size(); i++)
for (size_t j = i + 1; j < particles.size(); j++) {
Vec3 r = particles[j].pos - particles[i].pos;
pe -= 6.674e-11 * particles[i].mass * particles[j].mass / r.norm();
}
return pe;
}
private:
void computeForces() {
for (auto& p : particles) p.resetForce();
size_t n = particles.size();
int nThreads;
// First pass: find out how many threads we'll get
#pragma omp parallel
{
#pragma omp single
nThreads = omp_get_num_threads();
}
// One force array per thread — no race conditions
std::vector<std::vector<Vec3>> threadForces(
nThreads, std::vector<Vec3>(n, Vec3(0, 0, 0)));
#pragma omp parallel
{
int tid = omp_get_thread_num();
auto& localF = threadForces[tid];
#pragma omp for schedule(dynamic)
for (size_t i = 0; i < n; i++) {
for (size_t j = i + 1; j < n; j++) {
Vec3 r = particles[j].pos - particles[i].pos;
Vec3 f = gravityModel->force(r,
particles[i].mass, particles[j].mass);
localF[i] += f;
localF[j] += f * -1.0;
}
}
}
// Reduce: sum all thread-local arrays into particle forces
for (int t = 0; t < nThreads; t++)
for (size_t i = 0; i < n; i++)
particles[i].addForce(threadForces[t][i]);
}
};