diff --git a/bh_tree_mpi/datastructures/BarnesHutTree.cpp b/bh_tree_mpi/datastructures/BarnesHutTree.cpp
index bc8ea32cb96a4820a97f10e3dfa7e0bb4150de71..5849fce845c361b0df47f17bdb5c4a2acd93b145 100644
--- a/bh_tree_mpi/datastructures/BarnesHutTree.cpp
+++ b/bh_tree_mpi/datastructures/BarnesHutTree.cpp
@@ -84,10 +84,13 @@ namespace nbody {
current->bodies.clear();
}
- void BarnesHutTree::splitNode(Node* current) {
- if (current->isSplitable()) {
+ bool BarnesHutTree::splitNode(Node* current) {
+ bool result = current->isSplitable();
+
+ if (result) {
split(current);
}
+ return result;
}
void BarnesHutTree::build(vector
bodies, Box domain) {
@@ -108,7 +111,6 @@ namespace nbody {
//iterate over existing boxes and split if it contains too much bodies
BarnesHutTree::splitSubtree(this->nodes->next);
this->update();
-
}
void BarnesHutTree::build(vector bodies) {
diff --git a/bh_tree_mpi/datastructures/BarnesHutTree.hpp b/bh_tree_mpi/datastructures/BarnesHutTree.hpp
index 17b03638184e198da366aa4b2e641258ca8aedca..85a81d3e7bf18935023825d82868d60e21e3b54f 100644
--- a/bh_tree_mpi/datastructures/BarnesHutTree.hpp
+++ b/bh_tree_mpi/datastructures/BarnesHutTree.hpp
@@ -12,7 +12,7 @@ namespace nbody {
class BarnesHutTree : public Tree {
protected:
static vector splitBB(Node* node);
- virtual void splitNode(Node* current);
+ static bool splitNode(Node* current);
virtual void update();
static void split(Node* current);
public:
diff --git a/bh_tree_mpi/datastructures/BarnesHutTreeThreaded.cpp b/bh_tree_mpi/datastructures/BarnesHutTreeThreaded.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e4353b2af61beea6835817c8c21bfb3f6d7b4a61
--- /dev/null
+++ b/bh_tree_mpi/datastructures/BarnesHutTreeThreaded.cpp
@@ -0,0 +1,130 @@
+#include
+#include
+#include
+#include "BarnesHutTreeThreaded.hpp"
+#include "Node.hpp"
+#include "PthreadSimulation.hpp"
+
+namespace nbody {
+ using namespace std;
+
+ BarnesHutTreeThreaded::BarnesHutTreeThreaded(int parallelId) : BarnesHutTree(parallelId) {
+ pthread_mutex_init(&this->nodesToProcess.mutex, NULL);
+ }
+
+ BarnesHutTreeThreaded::~BarnesHutTreeThreaded() {
+ pthread_mutex_destroy(&this->nodesToProcess.mutex);
+ }
+
+ void BarnesHutTreeThreaded::addNodeToProcess(Node* node, NodesToProcess* store) {
+ pthread_mutex_lock(&store->mutex);
+ store->toProcess.push_back(node);
+ pthread_mutex_unlock(&store->mutex);
+ }
+
+ Node* BarnesHutTreeThreaded::getNodeToProcess(NodesToProcess* store) {
+ Node* result;
+
+ pthread_mutex_lock(&store->mutex);
+ if (store->toProcess.empty()) {
+ result = NULL;
+ } else {
+ result = store->toProcess.back();
+ store->toProcess.pop_back();
+ vector::iterator it = std::find(store->processing.begin(), store->processing.end(), pthread_self());
+ if (it == store->processing.end()) {
+ store->processing.push_back(pthread_self());
+ }
+ }
+ pthread_mutex_unlock(&store->mutex);
+ return result;
+ }
+
+ void BarnesHutTreeThreaded::setNodeProcessingFinished(NodesToProcess* store) {
+ pthread_mutex_lock(&store->mutex);
+ vector::iterator it = std::find(store->processing.begin(), store->processing.end(), pthread_self());
+ if (it != store->processing.end()) {
+ store->processing.erase(it);
+ }
+ pthread_mutex_unlock(&store->mutex);
+ }
+
+ bool BarnesHutTreeThreaded::hasNodeProcessingFinished(NodesToProcess* store) {
+ bool finished;
+
+ pthread_mutex_lock(&store->mutex);
+ finished = store->processing.empty() && store->toProcess.empty();
+ pthread_mutex_unlock(&store->mutex);
+ return finished;
+ }
+
+ void BarnesHutTreeThreaded::updateNode(Node* current) {
+ current->representative.id = ULONG_MAX;
+ current->representative.mass = 0.0;
+ current->representative.position[0] = 0.0;
+ current->representative.position[1] = 0.0;
+ current->representative.position[2] = 0.0;
+ for (unsigned int i = 0; i < current->bodies.size(); i++) {
+ current->representative.mass += current->bodies[i].mass;
+ for (int j = 0; j < 3; j++) {
+ current->representative.position[j] += current->bodies[i].position[j] * current->bodies[i].mass;
+ }
+ }
+ for (int j = 0; j < 3; j++) {
+ if (current->representative.mass > FLT_EPSILON) {
+ current->representative.position[j] /= current->representative.mass;
+ } else {
+ current->representative.position[j] = 0.0;
+ }
+ }
+ }
+
+ void* BarnesHutTreeThreaded::build(void* data) {
+ NodesToProcess* toProcess = (NodesToProcess*) data;
+
+ while (!BarnesHutTreeThreaded::hasNodeProcessingFinished(toProcess)) {
+ Node* current = BarnesHutTreeThreaded::getNodeToProcess(toProcess);
+
+ if (current != NULL) {
+ updateNode(current);
+ if (BarnesHutTree::splitNode(current)) {
+ Node* child = current->next;
+
+ while (child != NULL) {
+ BarnesHutTreeThreaded::addNodeToProcess(child, toProcess);
+ child = child->nextSibling;
+ }
+ }
+ }
+ }
+ return NULL;
+ }
+
+ void BarnesHutTreeThreaded::clearNodesToProcess() {
+ this->nodesToProcess.processing.clear();
+ this->nodesToProcess.toProcess.clear();
+ }
+
+ void BarnesHutTreeThreaded::build(vector bodies, Box domain) {
+ this->clean();
+ if (bodies.empty()) return;
+ //insert root node
+ this->nodes->insertAfter(new Node(this));
+ //assign bodies to root node
+ this->nodes->next->bodies = bodies;
+ //setup proper bounding box
+ this->nodes->next->bb = domain;
+ this->nodes->next->extendBBforBodies();
+ this->nodes->next->extendBBtoCube();
+ this->nodes->next->afterSubtree = this->nodes->next->next;
+ this->clearNodesToProcess();
+ this->nodesToProcess.toProcess.push_back(this->nodes->next);
+ for (int i = 0; i < this->simulation->getNumberOfProcesses(); i++) {
+ pthread_create((&((PthreadSimulation*) this->simulation)->threads[i]), NULL, BarnesHutTreeThreaded::build, &this->nodesToProcess);
+ }
+ //iterate over existing boxes and split if it contains too much bodies
+ //BarnesHutTree::splitSubtree(this->nodes->next);
+ //this->update();
+ }
+
+}
diff --git a/bh_tree_mpi/datastructures/BarnesHutTreeThreaded.hpp b/bh_tree_mpi/datastructures/BarnesHutTreeThreaded.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..317b223cdd9f70711fe1994e01d7e08fd0c6a948
--- /dev/null
+++ b/bh_tree_mpi/datastructures/BarnesHutTreeThreaded.hpp
@@ -0,0 +1,36 @@
+#ifndef BARNES_HUT_TREE_THREADED_HPP
+#define BARNES_HUT_TREE_THREADED_HPP
+
+#include
+#include "BarnesHutTree.hpp"
+
+namespace nbody {
+ using namespace std;
+
+ typedef struct _NodesToProcess {
+ pthread_mutex_t mutex;
+ vector toProcess;
+ vector processing;
+ } NodesToProcess;
+
+ class BarnesHutTreeThreaded : public BarnesHutTree {
+ friend class PthreadSimulation;
+ protected:
+ NodesToProcess nodesToProcess;
+
+ static void splitSubtree(Node* root);
+ static void* build(void* data);
+ static void updateNode(Node* current);
+ static void addNodeToProcess(Node* node, NodesToProcess* store);
+ static Node* getNodeToProcess(NodesToProcess* store);
+ static void setNodeProcessingFinished(NodesToProcess* store);
+ static bool hasNodeProcessingFinished(NodesToProcess* store);
+ virtual void clearNodesToProcess();
+ public:
+ BarnesHutTreeThreaded(int parallelId);
+ virtual ~BarnesHutTreeThreaded();
+ virtual void build(vector bodies, Box domain);
+ };
+}
+
+#endif
diff --git a/bh_tree_mpi/datastructures/Node.hpp b/bh_tree_mpi/datastructures/Node.hpp
index 39328b10573db8b3cde99b889517baeb92f8fa02..82ff6da473c202bcb14ef0d6979259982a36b978 100644
--- a/bh_tree_mpi/datastructures/Node.hpp
+++ b/bh_tree_mpi/datastructures/Node.hpp
@@ -15,6 +15,7 @@ namespace nbody {
class Node {
friend class Tree;
friend class BarnesHutTree;
+ friend class BarnesHutTreeThreaded;
protected:
Box bb;
vector bodies;
diff --git a/bh_tree_mpi/simulation/ReadWriteLock.cpp b/bh_tree_mpi/datastructures/ReadWriteLock.cpp
similarity index 100%
rename from bh_tree_mpi/simulation/ReadWriteLock.cpp
rename to bh_tree_mpi/datastructures/ReadWriteLock.cpp
diff --git a/bh_tree_mpi/simulation/ReadWriteLock.hpp b/bh_tree_mpi/datastructures/ReadWriteLock.hpp
similarity index 100%
rename from bh_tree_mpi/simulation/ReadWriteLock.hpp
rename to bh_tree_mpi/datastructures/ReadWriteLock.hpp
diff --git a/bh_tree_mpi/datastructures/Tree.cpp b/bh_tree_mpi/datastructures/Tree.cpp
index 5fe2a165300cfd145fd37ee19a8f26793bd32755..782cba22b796bb94985ad9a697a34a7d96151903 100644
--- a/bh_tree_mpi/datastructures/Tree.cpp
+++ b/bh_tree_mpi/datastructures/Tree.cpp
@@ -4,6 +4,7 @@
#include
#include "Tree.hpp"
#include "Node.hpp"
+#include "Simulation.hpp"
namespace nbody {
using namespace std;
@@ -13,6 +14,7 @@ namespace nbody {
this->nodes = new Node(this);
this->maxLeafBodies = 16;
this->parallelId = parallelId;
+ this->simulation = NULL;
}
Tree::~Tree() {
@@ -20,6 +22,10 @@ namespace nbody {
delete this->nodes;
}
+ void Tree::setSimulation(Simulation* simulation) {
+ this->simulation = simulation;
+ }
+
void Tree::clean() {
//remove all nodes; refresh dummy first node
while (this->nodes->next != this->nodes) {
diff --git a/bh_tree_mpi/datastructures/Tree.hpp b/bh_tree_mpi/datastructures/Tree.hpp
index 2d695c2bdcd6623dd4a899a972c46500d1589454..60beb7b7346f1c3025f8e50cee94049b6b2052f4 100644
--- a/bh_tree_mpi/datastructures/Tree.hpp
+++ b/bh_tree_mpi/datastructures/Tree.hpp
@@ -13,16 +13,20 @@ namespace nbody {
using namespace std;
class Node;
+ class Simulation;
class Tree {
friend class Node;
+ friend class PthreadSimulation;
protected:
Node* nodes;
unsigned int maxLeafBodies;
int parallelId;
+ Simulation* simulation;
public:
Tree(int parallelId);
virtual ~Tree();
+ virtual void setSimulation(Simulation* simulation);
virtual void clean();
virtual void build(vector bodies) = 0;
virtual void build(vector bodies, Box domain) = 0;
diff --git a/bh_tree_mpi/simulation/PthreadSimulation.cpp b/bh_tree_mpi/simulation/PthreadSimulation.cpp
index b0eb66e04334d73bf3367353d623135a70d00a54..46d3480d02bc503bbb80eeb786ba395f031269bb 100644
--- a/bh_tree_mpi/simulation/PthreadSimulation.cpp
+++ b/bh_tree_mpi/simulation/PthreadSimulation.cpp
@@ -1,6 +1,7 @@
#include
#include
#include
+#include "BarnesHutTreeThreaded.hpp"
namespace nbody {
using namespace std;
@@ -9,6 +10,7 @@ namespace nbody {
}
PthreadSimulation::~PthreadSimulation() {
+ delete this->tree;
}
void PthreadSimulation::initialize(string inputFile) {
@@ -22,9 +24,13 @@ namespace nbody {
this->threads.push_back(thread);
}
+ this->tree = new BarnesHutTreeThreaded(-1);
+ this->tree->simulation = this;
}
void PthreadSimulation::cleanup() {
+ delete this->tree;
+ this->tree = NULL;
pthread_exit(NULL);
}
diff --git a/bh_tree_mpi/simulation/PthreadSimulation.hpp b/bh_tree_mpi/simulation/PthreadSimulation.hpp
index af35afc5759c54f4b5d19da7feb3bb36560e7c45..8c0884e6f5f61c4178c45751a01b24c4c8d77bbe 100644
--- a/bh_tree_mpi/simulation/PthreadSimulation.hpp
+++ b/bh_tree_mpi/simulation/PthreadSimulation.hpp
@@ -8,6 +8,7 @@
namespace nbody {
class PthreadSimulation : public Simulation {
+ friend class BarnesHutTreeThreaded;
protected:
vector threads;
public: