CellModules
genericconnectionplugin.hpp
Go to the documentation of this file.
1#ifndef MECACELL_GENERICCONNECTIONPLUGIN_HPP
2#define MECACELL_GENERICCONNECTIONPLUGIN_HPP
3#include <future>
4#include <memory>
5#include <utility>
6#include <vector>
10//#include "utilities/external/tsl/ordered_map.h"
11
12namespace MecaCell {
17static double GRIDSIZE = 120;
18template <typename Cell, template <class> class GenericConnection>
20 const size_t MIN_CHUNK_SIZE = 5;
21 const size_t AVG_TASKS_PER_THREAD = 3;
22 // tsl::ordered_map<ordered_pair<Cell *>, std::unique_ptr<GenericConnection<Cell>>>
23 // connections;
25 std::unique_ptr<GenericConnection<Cell>>>
28
29 std::mutex connectionMutex;
30
31 bool collisionCheck = true;
32
33 // a callback called at every new connection
34 std::function<void(GenericConnection<Cell> *)> newConnectionCallback =
35 [](GenericConnection<Cell> *) {};
36
44 void setNewConnectionCallback(std::function<void(GenericConnection<Cell> *)> f) {
46 }
47
48 /* *******
49 * HOOKS
50 * *******/
51 template <typename W> void preBehaviorUpdate(W *w) {
52 w->threadpool.autoChunks(w->cells, 100, 5,
53 [dt = w->getDt()](auto &c) { c->body.updateInternals(dt); });
54 w->threadpool.waitUntilLast();
55 }
56
57 template <typename W> void endUpdate(W *w) {
58 unsigned int nbIterations = 2;
59
61
63 savedForces.reserve(w->cells.size()); // first we save the cell forces and torque
64 for (auto &c : w->cells) {
65 savedForces.push_back(
66 std::make_pair<Vec, Vec>(c->getBody().getForce(), c->getBody().getTorque()));
67 c->getBody().resetForce();
68 c->getBody().resetTorque();
69 }
70
72 double subdt = w->getDt() / static_cast<double>(nbIterations);
73 for (unsigned int i = 0; i < nbIterations; ++i) {
74 // for (auto &c : connections) c.second->update(subdt);
75 w->threadpool.autoChunks(connections, 100, 5,
76 [subdt](auto &c) { c.second->update(subdt); });
77 w->threadpool.waitUntilLast();
78 for (size_t j = 0; j < w->cells.size(); ++j) {
79 auto &c = w->cells[j];
80 c->body.receiveForce(savedForces[j].first);
81 c->body.receiveTorque(savedForces[j].second);
82 }
83 w->allForcesHaveBeenAppliedToCells();
84 for (auto &c : w->cells) {
85 c->body.updatePositionsAndOrientations(subdt);
86 c->body.resetForce();
87 c->body.resetTorque();
88 }
89 }
90 }
91
93
99 auto ptr = std::make_unique<GenericConnection<Cell>>(cells);
100 auto *newConnection = ptr.get();
101 connections[cells] = std::move(ptr);
102 cells.first->connectedCells.insert(cells.second);
103 cells.second->connectedCells.insert(cells.first);
104 cells.first->body.cellConnections.push_back(newConnection);
105 cells.second->body.cellConnections.push_back(newConnection);
106 newConnectionCallback(newConnection);
107 }
114 void disconnect(const ordered_pair<Cell *> &cells, GenericConnection<Cell> *conn) {
115 eraseFromVector(conn, cells.first->body.cellConnections);
116 eraseFromVector(conn, cells.second->body.cellConnections);
117 cells.first->eraseConnectedCell(cells.second);
118 cells.second->eraseConnectedCell(cells.first);
119 connections.erase(cells);
120 assert(!connections.count(cells));
121 }
123 for (auto &c : connections) {
124 }
125 }
132 template <typename W> void checkForCellCellConnections(W &world) {
133 // TODO: try with mutexes instead of colored grid (every batch is a task but there
134 // is
135 // a shared_mutex for newConnections)
136 const double NEW_CONNECTION_THRESHOLD = 1.0 - 1e-10;
137 if (GRIDSIZE > 0) {
139 for (const auto &c : world.cells) grid.insert(c);
140 int minCellPerBatch = 0;
141 if (world.threadpool.getNbThreads() > 0)
142 minCellPerBatch = world.cells.size() / (10 * 8.0);
143 auto gridCells = grid.getThreadSafeGrid(minCellPerBatch);
144 for (auto &color : gridCells) {
146 newConnectionsFutures; // we collect all the futures
147 newConnectionsFutures.reserve(color.size());
148 for (auto &batch : color)
149 if (batch.size() > 1)
150 newConnectionsFutures.push_back(world.threadpool.enqueueWithFuture([&] {
151 std::vector<ordered_pair<Cell *>> newConns;
152 for (size_t i = 0; i < batch.size(); ++i) {
153 for (size_t j = i + 1; j < batch.size(); ++j) {
154 auto op = make_ordered_cell_pair(batch[i], batch[j]);
155 Vec AB = op.second->getPosition() - op.first->getPosition();
156 double sqDistance = AB.sqlength();
157 if (sqDistance < std::pow(op.first->body.getBoundingBoxRadius() +
158 op.second->body.getBoundingBoxRadius(),
159 2)) {
160 if (!op.first->isConnectedTo(op.second) && op.first != op.second) {
161 double dist = sqrt(sqDistance);
162 Vec dir = AB / dist;
163 auto d0 = op.first->body.getPreciseMembraneDistance(dir);
164 auto d1 = op.second->body.getPreciseMembraneDistance(-dir);
165 if (dist < NEW_CONNECTION_THRESHOLD * (d0 + d1))
166 newConns.push_back(op);
167 }
168 }
169 }
170 }
171 return std::move(newConns);
172 }));
173 for (auto &ncf : newConnectionsFutures) // and wait for their accomplishment
174 for (const auto &nc : ncf.get()) createConnection(nc);
175 }
176 } else {
177 auto &batch = world.cells;
178 for (size_t i = 0; i < batch.size(); ++i) {
179 for (size_t j = i + 1; j < batch.size(); ++j) {
180 auto op = make_ordered_cell_pair(batch[i], batch[j]);
181 Vec AB = op.second->getPosition() - op.first->getPosition();
182 double sqDistance = AB.sqlength();
183 if (sqDistance < std::pow(op.first->body.getBoundingBoxRadius() +
184 op.second->body.getBoundingBoxRadius(),
185 2)) {
186 if (!op.first->isConnectedTo(op.second) && op.first != op.second) {
187 double dist = sqrt(sqDistance);
188 Vec dir = AB / dist;
189 auto d0 = op.first->body.getPreciseMembraneDistance(dir);
190 auto d1 = op.second->body.getPreciseMembraneDistance(-dir);
191 if (dist < NEW_CONNECTION_THRESHOLD * (d0 + d1)) createConnection(op);
192 }
193 }
194 }
195 }
196 }
197 }
198
206 template <typename W> void updateCellCellConnections(W &) {
207 std::vector<std::pair<ordered_pair<Cell *>, GenericConnection<Cell> *>> toDisconnect;
208 for (auto &con : connections) {
209 if (!con.second->unbreakable) {
210 if (con.second->area <= 0) {
211 toDisconnect.push_back(std::make_pair(con.first, con.second.get()));
212 } else if (con.first.first->getBody().getConnectedCell(con.second->direction) !=
213 con.first.second ||
214 con.first.second->getBody().getConnectedCell(-con.second->direction) !=
215 con.first.first) {
216 toDisconnect.push_back(std::make_pair(con.first, con.second.get()));
217 }
218 }
219 }
220 for (auto &c : toDisconnect) disconnect(c.first, c.second);
221 }
222
223 template <typename W> void preDeleteDeadCellsUpdate(W *w) {
224 for (auto &c : w->cells) {
225 if (c->isDead()) {
226 auto cctmp(c->body.cellConnections);
227 for (auto &connection : cctmp) {
228 auto *c0 = connection->cells.first;
229 auto *c1 = connection->cells.second;
230 eraseFromVector(connection, c0->body.cellConnections);
231 eraseFromVector(connection, c1->body.cellConnections);
232 c0->connectedCells.erase(c1);
233 c1->connectedCells.erase(c0);
234 assert(c0->id != c1->id);
235 connections.erase(connection->cells);
236 }
237 }
238 }
239 }
240};
241} // namespace MecaCell
242
243#endif
Infinite grid of fixed cell size for space partitioning.
Definition: grid.hpp:21
std::array< vector< vector< O > >, 8 > getThreadSafeGrid() const
Definition: grid.hpp:39
void insert(V &&k, const O &o)
Definition: grid.hpp:75
general purpose 3D vector/point class.
Definition: vector3D.h:20
double sqlength() const
compute the square length of the current vector (faster than length)
Definition: vector3D.h:265
A simple vector class template.
Definition: std.hpp:290
void reserve(size_t newCapacity)
Reserves storage for the specified number of elements.
Definition: std.hpp:372
void push_back(const T &value)
Adds an element to the end of the vector.
Definition: std.hpp:304
this file contains various miscellanious utility functions & helpers *
ordered_pair< T * > make_ordered_cell_pair(T *a, T *b)
T * ptr(T &obj)
returns a pointer (transforms reference into pointer)
Definition: utils.hpp:32
void eraseFromVector(const T &elem, std::deque< T > &vec)
Definition: utils.hpp:65
static double GRIDSIZE
Embedded plugin that will handle the collision detection routines. Parallel code.
double sqrt(double x)
Computes the square root of a number.
Definition: std.hpp:32
double pow(double base, double exponent)
Computes the power of a number.
Definition: std.hpp:43
std::mutex connectionMutex
connections. The ordered_hash_map is to enforce determinism.
void updateCellCellConnections(W &)
updates (compute forces) the connections and delete the resolved ones (when cells are not in contact ...
std::function< void(GenericConnection< Cell > *)> newConnectionCallback
void checkForCellCellConnections(W &world)
we check for any cell cell collision or adhesion
void setNewConnectionCallback(std::function< void(GenericConnection< Cell > *)> f)
Sets a callback function to be called at each connection creation. Can be used to override the defaul...
void disconnect(const ordered_pair< Cell * > &cells, GenericConnection< Cell > *conn)
Disconnect two cells.
void createConnection(const ordered_pair< Cell * > &cells)
create and register a contact surface connection between twoe cells
ordered_hash_map< ordered_pair< Cell * >, std::unique_ptr< GenericConnection< Cell > > > connections