CellModules
volumebody.hpp
Go to the documentation of this file.
1#ifndef VOLUMEMEMBRANE_HPP
2#define VOLUMEMEMBRANE_HPP
3#include <map>
4#include <utility>
5#include <vector>
6#include "cellcellconnectionmanager.hpp"
7#include "contactsurface.hpp"
10
11#define FOUR_THIRD_PI 4.1887902047863909846168578443726705
12
13#define MIN_MODEL_CONNECTION_SIMILARITY 0.8
14
15namespace MecaCell {
16template <typename Cell> class VolumeMembrane {
17 /********************** VolumeMembrane class template **********************/
18
19 CREATE_METHOD_CHECKS(getAdhesionWith);
20 template <typename C> struct SFINAE {
21 static constexpr bool hasPreciseAdhesion = has_getAdhesionWith_signatures<
22 C, double(C *, double, double), float(C *, float, float),
23 double(const C *, double, double), float(const C *, float, float)>::value;
24 static constexpr bool hasAdhesion =
25 has_getAdhesionWith_signatures<C, double(C *), float(C *), double(const C *),
26 float(const C *)>::value;
27
28 // different precision level for getAdhesionWith
29 // precise : takes a pointer to the other cell + the orientation of the connection
30 template <typename T = double>
31 static inline typename enable_if<hasPreciseAdhesion, T>::type getAdhesion(
32 const Cell *a, const Cell *b, const Vec &ABnorm) {
33 const auto B = a->getOrientation();
34 bool zNeg = ABnorm.dot(B.X.cross(B.Y)) < 0;
35 double phi = acos(ABnorm.dot(B.Y));
36 double teta = zNeg ? acos(ABnorm.dot(B.X)) : M_PI * 2.0 - acos(ABnorm.dot(B.X));
37 return a->getAdhesionWith(b, teta, phi);
38 }
39 // not precise: takes a pointer to the other cell
40 template <typename T = double, typename... Whatever>
41 static inline typename enable_if<!hasPreciseAdhesion && hasAdhesion, T>::type
42 getAdhesion(const Cell *a, const Cell *b, Whatever...) {
43 return a->getAdhesionWith(b);
44 }
45 // not even declared: always 0
46 template <typename T = double, typename... Whatever>
47 static inline
48 typename enable_if<!hasPreciseAdhesion && !hasAdhesion, T>::type getAdhesion(
49 Whatever...) {
50 return 0.0;
51 }
52 };
53
54 public:
55 using CCCM = CellCellConnectionManager_map<Cell, ContactSurface<Cell>>;
56 friend CCCM;
57 friend struct ContactSurface<Cell>;
58 using CellCellConnectionType = typename CCCM::ConnectionType;
59 using CellCellConnectionContainer = typename CCCM::CellCellConnectionContainer;
60 static const bool forcesOnMembrane =
61 false; // are forces applied directly to membrane or to the cell's center?
62
63 protected:
66
67 // params
68 double incompressibility = 0.003;
70
71 // internal stuff
74 // dynamic target radius:
77 static constexpr double MAX_DYN_RADIUS_RATIO = 2.0;
78 // this is the effective Radius, the one we deduce from the membrane area:
80 double currentArea = 4.0 * M_PI * restRadius * restRadius;
83 double pressure = 0;
84
85 public:
88 : cell(c),
98 pressure(sm.pressure){};
99
100 /**********************************************************
101 GET
102 ***********************************************************/
103 /************************ basics **************************/
104 inline Cell *getCell() { return cell; }
106 inline double getStiffness() const { return membraneStiffness; }
107 inline double getRestRadius() const { return restRadius; }
108 inline double getBaseRadius() const { return baseRadius; }
109 inline double getDeducedRadius() const { return deducedRadius; }
110 inline double getDynamicRadius() const { return dynamicRadius; }
111 inline double getBoundingBoxRadius() const { return dynamicRadius; };
112 inline double getPressure() const { return pressure; }
113 inline double getSqRestRadius() const { return restRadius * restRadius; }
114 inline double getCurrentVolume() const { return currentVolume; }
115 inline double getRestVolume() const { return restVolume; }
116 inline double getCurrentArea() const { return currentArea; }
117
118 /************************ computed **************************/
119 void division() {
122 }
123
124 pair<Cell *, double> getConnectedCellAndMembraneDistance(const Vec &d) const {
125 // /!\ assumes that d is normalized
126 Cell *closestCell = nullptr;
127 double closestDist = dynamicRadius;
128 for (auto &cc : cccm.cellConnections) {
129 auto con = CCCM::getConnection(cc);
130 auto normal = cell == con->cells.first ? -con->normal : con->normal;
131 double dot = normal.dot(d);
132 if (dot < 0) {
133 const auto &midpoint =
134 cell == con->cells.first ? con->midpoint.first : con->midpoint.second;
135 double l = -midpoint / dot;
136 if (l < closestDist) {
137 closestDist = l;
138 closestCell = con->cells.first == cell ? con->cells.second : con->cells.first;
139 }
140 }
141 }
142 return {closestCell, closestDist};
143 }
144
145 inline Cell *getConnectedCell(const Vec &d) const {
146 return get<0>(getConnectedCellAndMembraneDistance(d));
147 }
148 inline double getPreciseMembraneDistance(const Vec &d) const {
149 return get<1>(getConnectedCellAndMembraneDistance(d));
150 }
151 inline double getRestArea() const { return (4.0 * M_PI * restRadius * restRadius); }
152 inline void computeRestVolume() {
154 }
155 inline double getBaseVolume() const {
157 }
158 inline double getRestMomentOfInertia() const {
159 return 0.4 * cell->mass * restRadius * restRadius;
160 }
161 inline double getMomentOfInertia() const { return getRestMomentOfInertia(); }
162 inline double getVolumeVariation() const { return restVolume - currentVolume; }
163
165 double volumeLoss = 0;
166 // cell connections
167 for (auto &cc : cccm.cellConnections) {
168 auto con = CCCM::getConnection(cc);
169 auto &midpoint =
170 cell == con->cells.first ? con->midpoint.first : con->midpoint.second;
171 auto h = dynamicRadius - midpoint;
172 volumeLoss += (M_PI * h / 6.0) * (3.0 * con->sqradius + h * h);
173 }
174 // TODO : soustraire les overlapps
176 currentVolume = baseVol - volumeLoss;
177 const double minVol = 0.1 * getRestVolume();
178 if (currentVolume < minVol) currentVolume = minVol;
179 }
180
181 double getVolume() const { return restVolume; }
182
184 double surfaceLoss = 0;
185 for (auto &cc : cccm.cellConnections) {
186 auto con = CCCM::getConnection(cc);
187 auto &midpoint =
188 cell == con->cells.first ? con->midpoint.first : con->midpoint.second;
189 surfaceLoss += 2.0 * M_PI * dynamicRadius * (dynamicRadius - midpoint) - con->area;
190 }
191 double baseArea = 4.0 * M_PI * dynamicRadius * dynamicRadius;
192 currentArea = baseArea - surfaceLoss;
193 // TODO : soustraire les overlapps, avoir une meilleure précision
194 const double minArea =
195 0.1 * getRestArea(); // garde fou en attendant de soustraire les overlaps
196 if (currentArea < minArea) currentArea = minArea;
197 deducedRadius = sqrt(currentArea / 4.0 * M_PI);
198 }
199
200 /**********************************************************
201 SET
202 ***********************************************************/
204 void setStiffness(double k) { membraneStiffness = k; }
205 void setRadius(double r) { restRadius = r; }
206 void setBaseRadius(double r) { baseRadius = r; }
207 void setRadiusRatio(double r) { restRadius = r * baseRadius; }
208 void setVolume(double v) { setRadius(cbrt(v / (4.0 * M_PI / 3.0))); }
209
210 /**********************************************************
211 UPDATE
212 ***********************************************************/
213 template <typename Integrator> void updatePositionsAndOrientations(double dt) {
214 // Before updating positions and orientations we compute the cureent pressure
216 double dA = currentArea - getRestArea();
217 double dV = getRestVolume() - currentVolume;
218 auto Fv = incompressibility * dV;
219 auto Fa = membraneStiffness * dA;
220 pressure = Fv / currentArea;
221 double dynSpeed = (dynamicRadius - prevDynamicRadius) / dt;
222 double c = 5.0;
223 dynamicRadius += dt * dt * (Fv - Fa - dynSpeed * c);
226 else if (dynamicRadius < restRadius)
228 cell->receiveTorque(-cell->getAngularVelocity() * 50.0);
229 Integrator::updatePosition(*cell, dt);
230 Integrator::updateOrientation(*cell, dt);
231 cell->markAsNotTested();
232 }
233
234 void resetForces() {
235 cell->force = Vec::zero();
236 cell->torque = Vec::zero();
237 }
238
239 void updateStats() {
243 }
244
245 /**********************************************************
246 CONNECTIONS
247 ***********************************************************/
248 /******************** between cells ***********************/
249 template <typename C = Cell, typename... T>
250 static inline double getAdhesion(T &&... t) {
251 return SFINAE<C>::getAdhesion(std::forward<T>(t)...);
252 }
253
254 template <typename SpacePartition>
256 vector<Cell *> &cells, CellCellConnectionContainer &cellCellConnections,
257 SpacePartition &grid) {
258 vector<ordered_pair<Cell *>> newConnections;
259 grid.clear();
260 for (const auto &c : cells) grid.insert(c);
261 auto gridCells = grid.getThreadSafeGrid();
262 for (auto &batch : gridCells) {
263 for (size_t i = 0; i < batch.size(); ++i) {
264 for (size_t j = 0; j < batch[i].size(); ++j) {
265 for (size_t k = j + 1; k < batch[i].size(); ++k) {
266 auto op = make_ordered_cell_pair(batch[i][j], batch[i][k]);
267 Vec AB = op.second->position - op.first->position;
268 double sqDistance = AB.sqlength();
269 if (sqDistance < pow(op.first->getConstMembrane().dynamicRadius +
270 op.second->getConstMembrane().dynamicRadius,
271 2)) {
272 if (!CCCM::areConnected(op.first, op.second) &&
273 !isInVector(op, newConnections) && op.first != op.second) {
274 double dist = sqrt(sqDistance);
275 Vec dir = AB / dist;
276 auto d0 = op.first->getConstMembrane().getPreciseMembraneDistance(dir);
277 auto d1 = op.second->getConstMembrane().getPreciseMembraneDistance(-dir);
278 if (dist < 0.99999999 * (d0 + d1)) {
279 newConnections.push_back(op);
280 }
281 }
282 }
283 }
284 }
285 }
286 }
287 for (const auto &nc : newConnections) {
288 CCCM::createConnection(cellCellConnections, nc,
289 make_ordered_cell_pair(nc.first, nc.second));
290 }
291 }
292
294 // we update forces & delete impossible connections (cells not in contact
295 // anymore...)
297 for (auto &cc : concon) {
298 CellCellConnectionType *con = CCCM::getConnection(cc);
299 con->update(dt);
300 if (con->area <= 0) {
301 toDisconnect.push_back(con);
302 }
303 }
304 for (CellCellConnectionType *c : toDisconnect) {
305 CCCM::disconnect(concon, c->cells.first, c->cells.second, c);
306 }
307 }
308
311 auto cop = c0->membrane.cccm.cellConnections;
312 for (auto &cc : cop) {
313 CCCM::disconnect(con, cc->cells.first, cc->cells.second, cc);
314 }
315 }
316};
317}
318
319#endif
PrimoCell< CellBody > Cell
Definition: Scenario.hpp:16
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
static Vector3D zero()
constructs a zero vector
Definition: vector3D.h:170
double dot(const Vector3D &v) const
dot product calculation
Definition: vector3D.h:54
pair< Cell *, double > getConnectedCellAndMembraneDistance(const Vec &d) const
Definition: volumebody.hpp:124
void setIncompressibility(double i)
Definition: volumebody.hpp:203
static const bool forcesOnMembrane
Definition: volumebody.hpp:60
void setVolume(double v)
Definition: volumebody.hpp:208
void updatePositionsAndOrientations(double dt)
Definition: volumebody.hpp:213
double getMomentOfInertia() const
Definition: volumebody.hpp:161
CellCellConnectionManager_map< Cell, ContactSurface< Cell > > CCCM
Definition: volumebody.hpp:55
double getBoundingBoxRadius() const
Definition: volumebody.hpp:111
double getVolumeVariation() const
Definition: volumebody.hpp:162
double getDynamicRadius() const
Definition: volumebody.hpp:110
double getPressure() const
Definition: volumebody.hpp:112
static double getAdhesion(T &&... t)
Definition: volumebody.hpp:250
double getCurrentArea() const
Definition: volumebody.hpp:116
double getPreciseMembraneDistance(const Vec &d) const
Definition: volumebody.hpp:148
void setStiffness(double k)
Definition: volumebody.hpp:204
double getBaseRadius() const
Definition: volumebody.hpp:108
static void checkForCellCellConnections(vector< Cell * > &cells, CellCellConnectionContainer &cellCellConnections, SpacePartition &grid)
Definition: volumebody.hpp:255
double getRestVolume() const
Definition: volumebody.hpp:115
static void updateCellCellConnections(CellCellConnectionContainer &concon, double dt)
Definition: volumebody.hpp:293
VolumeMembrane(Cell *c, const VolumeMembrane &sm)
Definition: volumebody.hpp:87
double getDeducedRadius() const
Definition: volumebody.hpp:109
double getCurrentVolume() const
Definition: volumebody.hpp:114
static void disconnectAndDeleteAllConnections(Cell *c0, CellCellConnectionContainer &con)
Definition: volumebody.hpp:309
void setRadiusRatio(double r)
Definition: volumebody.hpp:207
double getRestRadius() const
Definition: volumebody.hpp:107
double getRestArea() const
Definition: volumebody.hpp:151
CREATE_METHOD_CHECKS(getAdhesionWith)
typename CCCM::CellCellConnectionContainer CellCellConnectionContainer
Definition: volumebody.hpp:59
Cell * getConnectedCell(const Vec &d) const
Definition: volumebody.hpp:145
CCCM & getCellCellConnectionManager()
Definition: volumebody.hpp:105
static constexpr double MAX_DYN_RADIUS_RATIO
Definition: volumebody.hpp:77
void setRadius(double r)
Definition: volumebody.hpp:205
typename CCCM::ConnectionType CellCellConnectionType
Definition: volumebody.hpp:58
double getBaseVolume() const
Definition: volumebody.hpp:155
void setBaseRadius(double r)
Definition: volumebody.hpp:206
double getSqRestRadius() const
Definition: volumebody.hpp:113
double getRestMomentOfInertia() const
Definition: volumebody.hpp:158
double getVolume() const
Definition: volumebody.hpp:181
double getStiffness() const
Definition: volumebody.hpp:106
Represents a cell in the simulation.
Definition: PrimoCell.hpp:53
A simple vector class template.
Definition: std.hpp:290
void push_back(const T &value)
Adds an element to the end of the vector.
Definition: std.hpp:304
void clear()
Clears the contents of the vector.
Definition: std.hpp:354
this file contains various miscellanious utility functions & helpers *
bool isInVector(const T &elem, const std::vector< T > &vec)
Definition: utils.hpp:62
ordered_pair< T * > make_ordered_cell_pair(T *a, T *b)
double cbrt(double x)
Computes the cube root of a number.
Definition: std.hpp:215
double acos(double x)
Computes the arc cosine of a number.
Definition: std.hpp:113
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
static constexpr double DEFAULT_CELL_RADIUS
Definition: config.hpp:12
static constexpr bool hasPreciseAdhesion
Definition: volumebody.hpp:21
static enable_if< hasPreciseAdhesion, T >::type getAdhesion(const Cell *a, const Cell *b, const Vec &ABnorm)
Definition: volumebody.hpp:31
static enable_if<!hasPreciseAdhesion &&!hasAdhesion, T >::type getAdhesion(Whatever...)
Definition: volumebody.hpp:48
static constexpr bool hasAdhesion
Definition: volumebody.hpp:24
static enable_if<!hasPreciseAdhesion &&hasAdhesion, T >::type getAdhesion(const Cell *a, const Cell *b, Whatever...)
Definition: volumebody.hpp:42
#define FOUR_THIRD_PI
Definition: volumebody.hpp:11