VPTissue Reference Manual
CellDivider.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2011-2016 Universiteit Antwerpen
3  *
4  * Licensed under the EUPL, Version 1.1 or as soon they will be approved by
5  * the European Commission - subsequent versions of the EUPL (the "Licence");
6  * You may not use this work except in compliance with the Licence.
7  * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl5
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the Licence is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the Licence for the specific language governing
13  * permissions and limitations under the Licence.
14  */
24 #include "CellDivider.h"
25 
26 #include "bio/Cell.h"
27 #include "bio/CellAttributes.h"
28 #include "bio/Edge.h"
29 #include "bio/Mesh.h"
30 #include "bio/NeighborNodes.h"
31 #include "bio/Node.h"
32 #include "bio/Wall.h"
33 #include "math/array3.h"
34 #include "math/constants.h"
35 #include "math/Geom.h"
36 #include "math/RandomEngine.h"
38 #include "sim/CoreData.h"
41 #include "util/misc/Exception.h"
42 #include "util/misc/log_debug.h"
43 
44 #include <trng/uniform01_dist.hpp>
45 #include <array>
46 #include <cassert>
47 #include <list>
48 #include <memory>
49 #include <string>
50 #include <vector>
51 
52 using namespace std;
53 using namespace SimPT_Sim;
54 using namespace boost::property_tree;
55 using namespace SimPT_Sim::Container;
56 
57 namespace {
58 
59 void AssignExistingNodesToSplitCells(Mesh* mesh, Cell* this_cell,
60  vector<Node*>& parent_nodes, vector<Node*>& daughter_nodes,
61  const array<Node*, 2>& new_node_index)
62 {
63  const auto start = find(parent_nodes.begin(), parent_nodes.end(), new_node_index[0]);
64  assert(start != parent_nodes.end()
65  && "The new intersection should already be in the list of parent nodes.");
66 
67  rotate(parent_nodes.begin(), start, parent_nodes.end());
68 
69  const auto stop = find(parent_nodes.begin(), parent_nodes.end(), new_node_index[1]);
70  assert(stop != parent_nodes.end()
71  && "The new intersection should already be in the list of parent nodes.");
72  assert(stop != parent_nodes.begin()
73  && "The two intersections are the same.");
74 
75  auto is_nb = [this_cell](const NeighborNodes& n) {
76  return (n.GetCell()->GetIndex() == this_cell->GetIndex());
77  };
78 
79  for (auto it = parent_nodes.begin() + 1; it != stop; it++) {
80  auto& owners = mesh->GetNodeOwningNeighbors(*it);
81  auto nb_it = find_if(owners.begin(), owners.end(), is_nb);
82  assert((nb_it != owners.end()) && "Node manipulation failure!");
83  owners.erase(nb_it);
84  daughter_nodes.push_back(*it);
85  }
86  parent_nodes.erase(parent_nodes.begin(), stop + 1);
87 }
88 
89 vector<Node*> ComputeIntersectNodes(Cell* cell, const array<double, 3>& axis)
90  {
91  const array<double, 3> centroid = cell->GetCentroid();
92  const array<double, 3> cross_prod = CrossProduct(axis, centroid - *(cell->GetNodes().back()));
93  double prev_cross_z = cross_prod[2];
94  vector<Node*> intersect_nodes;
95  vector<Node*>& nodes = cell->GetNodes();
96  for (unsigned int i = 0U; i < nodes.size(); i++) {
97  // cross product to detect position of division
98  const array<double, 3> cross = CrossProduct(axis, centroid - *nodes.at(i));
99  // If the cross product changes sign, the line from centroid to node
100  // has crossed the axis going from the previous node to the current one.
101  if (cross[2] * prev_cross_z < 0) {
102  intersect_nodes.push_back(nodes.at(i));
103  }
104  prev_cross_z = cross[2];
105  }
106  return intersect_nodes;
107  }
108 
109 vector<Node*> ComputeTwoIntersectNodes(Cell* cell, const array<double, 3>& axis, std::vector<Node*> intersect_nodes)
110  {
111  std::vector<Node*> new_intersect_nodes;
112 
113  // ------------------------------------------------------------------------
114  // calculate intersection points of axis
115  // & calculate on which side of the long axis each intersection point lies
116  // ------------------------------------------------------------------------
117  std::vector<Node*>& nodes = cell->GetNodes();
118  GeoData geo_dat = cell->GetGeoData();
119  std::array<double, 3> long_axis = std::get<1>(geo_dat.GetEllipseAxes());
120 
121  const auto from = cell->GetCentroid();
122  const auto to = from + axis;
123 
124  std::map<Node*, double> intersect_points;
125  for (Node* nn_ptr : intersect_nodes) {
126  // -----------------------------------------------------------------------
127  // Intersection between division axis and edge from this node
128  // to its predecessor.
129  // -----------------------------------------------------------------------
130  const auto nn_it = make_const_circular(nodes, find(nodes.begin(), nodes.end(), nn_ptr));
131  const auto pr_it = prev(nn_it);
132  const auto n_vec = Geom::Intersection(from, to, *(*nn_it), *(*pr_it));
133 
134  // ------------------------------
135  // Calculate distance to centroid
136  // ------------------------------
137  double dist = sqrt(pow((cell->GetCentroid()[0] - n_vec[0]), 2) +
138  pow((cell->GetCentroid()[1] - n_vec[1]), 2));
139 
140  // ------------------------------------------------------------
141  // Calculate which side of the long axis the intersection is on
142  // ------------------------------------------------------------
143  const array<double, 3> cross = CrossProduct(long_axis, cell->GetCentroid() - *nn_ptr);
144  int sign = SimPT_Sim::Util::signum(cross[2]);
145 
146  // ----------------------------------------------------------------
147  // Set distance - if sign or cross was -, + if sign of cross was +
148  // ----------------------------------------------------------------
149  dist *= sign;
150  intersect_points[nn_ptr] = dist;
151  }
152 
153  // --------------------------------------------------------------------
154  // Choose closest intersection points on either side of the long axis
155  // --------------------------------------------------------------------
156  Node* node1;
157  double node1_dist = std::numeric_limits<double>::infinity();
158  Node* node2;
159  double node2_dist = std::numeric_limits<double>::infinity();
160  for (auto entry : intersect_points) {
161  if(entry.second >= 0) {
162  if(entry.second < node1_dist) {
163  node1 = entry.first;
164  node1_dist = entry.second;
165  }
166  } else {
167  if(abs(entry.second) < node2_dist) {
168  node2 = entry.first;
169  node2_dist = abs(entry.second);
170  }
171  }
172  }
173 
174  new_intersect_nodes.push_back(node1);
175  new_intersect_nodes.push_back(node2);
176  return new_intersect_nodes;
177 
178  }
179 
180 } // anonymous namespace
181 
182 
183 namespace SimPT_Sim {
184 
185 CellDivider::CellDivider(const CoreData& cd)
186 {
187  Initialize(cd);
188 }
189 
190 CellDivider::CellDivider(Mesh* mesh)
191 {
192  Initialize(mesh);
193 }
194 
195 void CellDivider::AddSharedWallNodes(array<array<double, 3>, 2>& new_node_vector,
196  array<Node*, 2>& new_node_index, vector<Node*>& parent_nodes, vector<Node*>& daughter_nodes)
197 {
198  //--------------------------------------------------------------------------
199  // Insert the nodes that start the shared wall, but remember these are different
200  // for parent and daughter because their traversal order is different in parent and daughter.
201  //--------------------------------------------------------------------------
202  parent_nodes.push_back(new_node_index[0]);
203  daughter_nodes.push_back(new_node_index[1]);
204 
205  //--------------------------------------------------------------------------
206  // Skip this for some of the models.
207  //--------------------------------------------------------------------------
208  if ( m_model_name != "Wortel"
209  && m_model_name != "Maize"
210  && m_model_name != "MaizeGRN"
211  && m_model_name != "WortelLight"
212  && m_model_name != "Blad"
213  && m_model_name != "WrapperModel") {
214 
215  // Add intermediate, extra nodes along the shared wall. Calculate the
216  // distance between new nodes to estimate the number of intermediate nodes.
217  // The factor 4.0 is there to keep tension on the walls;
218  // this is a hidden parameter and should be made explicit later on.
219 
220  const double dist = Norm(new_node_vector[1] - new_node_vector[0]);
221  const double tnd = abs(m_target_node_distance);
222  const int n = (tnd > SimPT_Sim::Util::small_real()) ? static_cast<int>((dist/tnd) / 4.0 + 0.5) : 0;
223  const double new_dist = dist / static_cast<double>(n + 1);
224  const auto nodevec = Normalize(new_node_vector[1] - new_node_vector[0]);
225 
226  // Note that wall nodes need to run in inverse order in parent
227  vector<Node*>::iterator ins_pos = daughter_nodes.end();
228  for (int i = 1; i <= n; i++) {
229  const array<double, 3> vec = new_node_vector[0] + i * new_dist * nodevec;
230  auto node = m_mesh->BuildNode(vec, false);
231  ins_pos = daughter_nodes.insert(ins_pos, node);
232  parent_nodes.push_back(node);
233  }
234  }
235 
236  //--------------------------------------------------------------------------
237  // Insert the final nodes of the shared wall, again taking traversal order into account.
238  //--------------------------------------------------------------------------
239  daughter_nodes.push_back(new_node_index[0]);
240  parent_nodes.push_back(new_node_index[1]);
241 }
242 
243 void CellDivider::AddSplitWalls(Cell* this_cell, Cell* neighbor_cell, int i,
244  array<Node*, 2>& new_node_ptr, array<Wall*, 4>& div_wall,
245  array<double, 2>& orig_length, array<double, 2>& orig_rest_length, array<double, 2>& orig_rest_length_init)
246 {
247  auto this_cell_walls = this_cell->GetWalls();
248  assert((neighbor_cell != nullptr) && "There has to be a neighbor_cell!");
249 
250  if (neighbor_cell && !this_cell_walls.empty() /* && !neighbor_cell->BoundaryPolP() */) {
251 
252  const auto is_of_nb =[neighbor_cell](Wall* w) {
253  return (w->GetC1() == neighbor_cell) || (w->GetC2() == neighbor_cell);
254  };
255 
256  //--------------------------------------------------------------------------
257  // Find the correct wall element. This is the wall between this cell and neighbor
258  // cell containing the intersection node.
259  // All intersection nodes have already been added to this cell.
260  //--------------------------------------------------------------------------
261  auto w = this_cell_walls.begin();
262  bool ok = false;
263  do {
264  w = find_if(w, this_cell_walls.end(), is_of_nb);
265 
266  if (w == this_cell_walls.end()) {
267  break;
268  }
269 
270  auto nodes = (*w)->GetC1()->GetNodes();
271  rotate(nodes.begin(), find(nodes.begin(), nodes.end(), (*w)->GetN1()), nodes.end());
272  auto secondNode = find(nodes.begin(), nodes.end(), (*w)->GetN2());
273 
274  for (auto it = nodes.begin(); it != next(secondNode); it++) {
275  if (*it == new_node_ptr[i]) {
276  ok = true;
277  break;
278  }
279  }
280  } while (!ok && ++w != this_cell_walls.end()); //Short circuiting to have the right w if ok.
281  assert((w != this_cell_walls.end()) && "No split wall element found!");
282 
283  //--------------------------------------------------------------------------
284  // Split it up, if we should (sometimes, the new node coincides with an
285  // existing node so we should not split up the Wall).
286  //--------------------------------------------------------------------------
287  if ((new_node_ptr[i] != (*w)->GetN1()) && (new_node_ptr[i] != (*w)->GetN2())) {
288  Wall* new_wall;
289 
290  //--------------------------------------------------------------------------
291  // Keep the length of the original wall; we need it to equally divide
292  // the transporter concentrations over the two daughter walls
293  //--------------------------------------------------------------------------
294  (*w)->SetLengthDirty();
295  orig_length[i] = (*w)->GetLength();
296  orig_rest_length[i] = (*w)->GetRestLength();
297  orig_rest_length_init[i] = (*w)->GetRestLengthInit();
298  if ((*w)->GetC1() == this_cell) {
299  new_wall = m_mesh->BuildWall((*w)->GetN1(),
300  new_node_ptr[i], this_cell, neighbor_cell);
301  } else {
302  new_wall = m_mesh->BuildWall((*w)->GetN1(),
303  new_node_ptr[i], neighbor_cell, this_cell);
304  }
305  (*w)->SetN1(new_node_ptr[i]);
306  (*w)->SetLengthDirty();
307  (*w)->SetRestLength((orig_rest_length[i] / orig_length[i])*(*w)->GetLength());
308  (*w)->SetRestLengthInit((orig_rest_length_init[i] / orig_length[i])*(*w)->GetLength());
309 
310  //--------------------------------------------------------------------------
311  //test SETWALLSTRENGTH transplant
312  //--------------------------------------------------------------------------
313  (*w)->SetStrength((*w)->GetStrength());
314  new_wall->SetStrength((*w)->GetStrength());
315  assert(new_wall->GetN1() != new_wall->GetN2() && "What the hell!");
316 
317  //--------------------------------------------------------------------------
318  // Give wall elements to appropriate cells.
319  //--------------------------------------------------------------------------
320  if (m_copy_wall) {
321  new_wall->WallAttributes::operator=(**w);
322  } else {
323  //--------------------------------------------------------------------------
324  // If wall contents are not copied, decide randomly which wall will
325  // be the "parent"; otherwise we will get biases (to the left), for
326  // example in the meristem growth model
327  //--------------------------------------------------------------------------
328  assert((m_cd.m_random_engine != nullptr) && "Random engine not initialized.");
329  if (m_uniform_generator() < 0.5) {
330  new_wall->WallAttributes::Swap(**w);
331  }
332  }
333  //--------------------------------------------------------------------------
334  // Remember the addresses of the new walls.
335  //--------------------------------------------------------------------------
336  this_cell->AddWall(new_wall);
337  neighbor_cell->AddWall(new_wall);
338  div_wall[2 * i + 0] = *w;
339  div_wall[2 * i + 1] = new_wall;
340 
341  //--------------------------------------------------------------------------
342  // Correct the walls associated with the nodes on the new wall
343  // Old wall should also be updated, as a node might have been added to split the wall
344  //--------------------------------------------------------------------------
345  m_mesh->UpdateNodeOwningWalls(*w);
346  m_mesh->UpdateNodeOwningWalls(new_wall);
347  }
348  }
349 }
350 
351 void CellDivider::ComputeIntersection(Cell* cell, vector<Node*> intersect_nodes,
352  const array<double, 3>& from, const array<double, 3>& to,
353  array<array<double, 3>, 2>& new_node_vector, array<Node*, 2>& new_node_ptr,
354  array<int, 2>& new_node_flag, array<Edge, 2>& intersect_edge)
355 {
356  int nnc = 0;
357 
358  //--------------------------------------------------------------------------
359  // Determine the intersection points and find out whether they (almost)
360  // coincide with existing points in which we will use those existing
361  // nodes to build the shared wall.
362  //--------------------------------------------------------------------------
363  vector<Node*>& nodes = cell->GetNodes();
364  for (Node* nn_ptr : intersect_nodes) {
365 
366  //--------------------------------------------------------------------------
367  // Intersection between division axis and edge from this node
368  // to its predecessor. Remember the edge gets divided.
369  //--------------------------------------------------------------------------
370  const auto nn_it = make_const_circular(nodes, find(nodes.begin(), nodes.end(), nn_ptr));
371  const auto pr_it = prev(nn_it);
372  const auto n_vec = Geom::Intersection(from, to, *(*nn_it), *(*pr_it));
373  intersect_edge[nnc] = Edge(*pr_it, *nn_it);
374 
375  //--------------------------------------------------------------------------
376  // Insert this new node if it is far enough (5% of element length)
377  // from one of the two existing nodes, else use existing node.
378  // new_node_flag == 0 : an actual new node needs to be created
379  // new_node_flag == 1 : node pointed to by new_node_location iterator is used
380  // new_node_flag == 2 : predecessor of node pointed to by new_node_location iterator is used
381  //--------------------------------------------------------------------------
382  const array<double, 3> nn = *(*nn_it);
383  const array<double, 3> pr = *(*pr_it);
384  const double tol = m_collapse_node_threshold * Norm(nn - pr);
385  if (Norm(nn - n_vec) <= tol) {
386  new_node_flag[nnc] = 1;
387  new_node_vector[nnc] = nn;
388  new_node_ptr[nnc] = *nn_it;
389  } else if (Norm(pr - n_vec) <= tol) {
390  new_node_flag[nnc] = 2;
391  new_node_vector[nnc] = pr;
392  new_node_ptr[nnc] = *pr_it;
393  } else {
394  new_node_flag[nnc] = 0;
395  new_node_vector[nnc] = n_vec;
396  new_node_ptr[nnc] = nullptr;
397  }
398 
399  nnc++;
400  }
401 }
402 
403 unsigned int CellDivider::DivideCells()
404 {
405  unsigned int division_count = 0U;
406 
407  // Copy current cells (vector of current cells gets updated
408  // by division so you cannot loop over it).
409  const vector<Cell*> current_cells { m_mesh->GetCells() };
410  // CellSplit tuple indicates whether to divide, whether
411  // to use a fixed axis, and what that axis must be.
412  for (auto const& cell : current_cells) {
413  auto tup = m_cell_split(cell);
414  if (get<0>(tup)) {
415  if (get<1>(tup)) {
416  DivideOverAxis(cell, get<2>(tup));
417  } else {
418  const auto axis = Orthogonalize(get<1>(cell->GetGeoData().GetEllipseAxes()));
419  DivideOverAxis(cell, axis);
420  }
421  division_count++;
422  }
423  }
424  return division_count;
425 }
426 
427 void CellDivider::DivideOverAxis(Cell* cell, const array<double, 3>& axis)
428 {
429  assert((m_cd.m_mesh != nullptr) && "Mesh not initialized.");
430 
431  //--------------------------------------------------------------------------
432  // First we need to find which edges get intersected by the division axis.
433  // The algorithm detects a change of sign in the cross product of the
434  // axis and a vector form to centroid to the node. If the sign flips, the
435  // edge from the previous node to the current node gets intersected. We
436  // store the iterators to the current node in the intersect_nodes.
437  //--------------------------------------------------------------------------
438  auto intersect_nodes = ComputeIntersectNodes(cell, axis);
439  assert((intersect_nodes.size() == 2) && "Can only handle two intersection points.");
440 
441  //--------------------------------------------------------------------------
442  // Division currently only works for two intersection points only. When there
443  // are more than two intersection points, the two points that are closest to the
444  // centroid on either side of the long axis of the cell are chosen as the
445  // intersection points.
446  // The division creates a new cell (one daughter) and morphs the parent
447  // into a new cell (the other daughter). We need to manage the parent's
448  // attributes (cell and some geometric properties) to be able to assign
449  // attributes for each of the daughters.
450  //--------------------------------------------------------------------------
451  if (intersect_nodes.size() != 2) {
452  // ----------------------------------------------------------------
453  // If there are less than two intersection points or the centroid
454  // is not in the interior of the cell, still throw exception
455  // ----------------------------------------------------------------
456  if((Geom::wn_PnPoly(cell->GetCentroid(), cell->GetNodes()) != 0)
457  && intersect_nodes.size() > 2)
458  {
459  intersect_nodes = ComputeTwoIntersectNodes(cell, axis, intersect_nodes);
460  } else {
461  const string msg = string(VL_HERE) + " exception:\nToo many intersection points.";
462  throw Exception(msg);
463  }
464  }
465 
466  //--------------------------------------------------------------------------
467  // Save parent's attributes to fix the daughter's after split.
468  //--------------------------------------------------------------------------
469  CellAttributes this_cell_old_attributes = *cell;
470 
471  //--------------------------------------------------------------------------
472  // Split geometry of parent (cell prior to split) along a line through the
473  // centroid in the direction of the axis to obtain the daughters (resp. cell
474  // after split and cell in return value).
475  //--------------------------------------------------------------------------
476  const auto from = cell->GetCentroid();
477  const auto to = from + axis;
478  Cell* daughter = SplitCell(cell, intersect_nodes, from, to);
479  cell->IncrementDivisionCounter();
480  daughter->IncrementDivisionCounter();
481 
482  //--------------------------------------------------------------------------
483  // Update daughter attributes.
484  //--------------------------------------------------------------------------
485  daughter->CellAttributes::operator=(this_cell_old_attributes);
486  // solute
487  const auto new_solute = cell->GetSolute() / sqrt(2.0);
488  cell->SetSolute(new_solute);
489  daughter->SetSolute(new_solute);
490  // target area
491  const auto new_t_area = cell->GetTargetArea() / 2.0;
492  cell->SetTargetArea(new_t_area);
493  daughter->SetTargetArea(new_t_area);
494  // target length
495  const auto new_t_length = cell->GetTargetLength() / sqrt(2.0);
496  cell->SetTargetLength(new_t_length);
497  daughter->SetTargetLength(new_t_length);
498  // Chemicals in cells and transporters in walls.
499  m_cell_daughters(daughter, cell);
500 }
501 
502 list<Cell*> CellDivider::GeometricSplitCell(Cell* cell, Node* node1, Node* node2)
503 {
504  vector<Node*> intersect_nodes;
505  vector<Node*> nodes = cell->GetNodes();
506  for (unsigned int i = 0; i < nodes.size(); i++) {
507  if (nodes.at(i) == node1 || nodes.at(i) == node2) {
508  intersect_nodes.push_back(nodes.at(i));
509  }
510  }
511 
512  Cell* newCell = SplitCell(cell, intersect_nodes, *node1, *node2);
513  cell->SetGeoDirty();
514  newCell->SetGeoDirty();
515  newCell->CellAttributes::operator=(*cell);
516 
517  list<Cell*> newCells;
518  newCells.push_back(cell);
519  newCells.push_back(newCell);
520 
521  return newCells;
522 }
523 
524 void CellDivider::Initialize(Mesh* mesh)
525 {
526  try {
527  assert( (mesh != nullptr) && "mesh pointer not ok.");
528  m_cd = CoreData();
529  m_collapse_node_threshold = 10e-12; //Due to floating point errors.
530  m_copy_wall = true;
531  m_mesh = mesh;
532  m_model_name = "";
533  m_target_node_distance = 0.0;
534 
535  }
536  catch(exception& e) {
537  const string here = string(VL_HERE) + " exception:\n";
538  throw Exception(here + e.what());
539  }
540 }
541 
542 void CellDivider::Initialize(const CoreData& cd)
543 {
544  try {
545  assert( cd.Check() && "CoreData not ok.");
546  m_cd = cd;
547  auto& p = m_cd.m_parameters;
548  m_mesh = m_cd.m_mesh.get();
549  const auto model_group = m_cd.m_parameters->get<string>("model.group", "");
550 
551  const auto factory = ComponentFactoryProxy::Create(model_group);
552  m_cell_daughters = factory->CreateCellDaughters(m_cd);
553  m_cell_split = factory->CreateCellSplit(m_cd);
554 
555  m_collapse_node_threshold = 0.05;
556  m_copy_wall = p->get<bool>("cell_mechanics.copy_wall");
557  m_model_name = p->get<string>("model.name");
558  m_target_node_distance = p->get<double>("cell_mechanics.target_node_distance");
559 
560  const trng::uniform01_dist<double> dist;
561  m_uniform_generator = m_cd.m_random_engine->GetGenerator(dist);
562  }
563  catch(exception& e) {
564  const string here = string(VL_HERE) + " exception:\n";
565  throw Exception(here + e.what());
566  }
567 }
568 
569 Node* CellDivider::InsertNewNodeAtIntersect(Cell* this_cell, Cell* neighbor_cell,
570  array<double, 3> node_vec, const Edge& intrsct_edge)
571 {
572  auto& this_cell_nodes = this_cell->GetNodes();
573  const bool at_boundary = m_mesh->IsAtBoundary(&intrsct_edge);
574  Node* node_ptr = m_mesh->BuildNode(node_vec, at_boundary);
575 
576  //--------------------------------------------------------------------------
577  // Insert new node in this cell in the appropriate position.
578  //--------------------------------------------------------------------------
579  const auto ins_pos_this_cell = find(this_cell_nodes.begin(), this_cell_nodes.end(), intrsct_edge.GetSecond());
580  assert(((ins_pos_this_cell != this_cell_nodes.begin() && *prev(ins_pos_this_cell) == intrsct_edge.GetFirst())
581  || this_cell_nodes.back() == intrsct_edge.GetFirst()) && "Error in insertion position!");
582  this_cell_nodes.insert(ins_pos_this_cell, node_ptr);
583 
584  //--------------------------------------------------------------------------
585  // Insert new node in neighbor cell. First, find the position of the first node.
586  //--------------------------------------------------------------------------
587  auto& nb_nodes = neighbor_cell->GetNodes();
588 #if (defined(__clang__) && defined(__APPLE__))
589  const auto ins_pos_nb_cell = find(nb_nodes.cbegin(), nb_nodes.cend(), intrsct_edge.GetFirst());
590 #else
591  const auto ins_pos_nb_cell = find(nb_nodes.begin(), nb_nodes.end(), intrsct_edge.GetFirst());
592 #endif
593 
594 #if (defined(__clang__) && defined(__APPLE__))
595  const auto cit = make_const_circular(nb_nodes.cbegin(), nb_nodes.cend(), ins_pos_nb_cell);
596 #else
597  const auto cit = make_const_circular(nb_nodes.begin(), nb_nodes.end(), ins_pos_nb_cell);
598 #endif
599  //--------------------------------------------------------------------------
600  // The node comes before or after the first (depending on whether the neighbor
601  // cell is a real cell or the boundary polygon this differs: you cannot simply
602  // deduce this by reversing the order from what it was in ''this cell''.
603  //--------------------------------------------------------------------------
604  if (*next(cit) == intrsct_edge.GetSecond()) {
605  nb_nodes.insert((next(cit)).get(), node_ptr);
606  } else {
607  assert((*prev(cit) == intrsct_edge.GetSecond()) && "Error in insertion position!");
608  nb_nodes.insert(cit.get(), node_ptr);
609  }
610 
611  return node_ptr;
612 }
613 
614 Cell* CellDivider::SplitCell(Cell* this_cell, vector<Node*> intersect_nodes,
615  const array<double, 3>& from, const array<double, 3>& to)
616 {
617  auto daughter = m_mesh->BuildCell();
618  auto& this_cell_nodes = this_cell->GetNodes();
619  auto& daughter_nodes = daughter->GetNodes();
620 
621  array<array<double, 3>, 2> new_node_vector;
622  array<Node*, 2> new_node_ptr;
623  array<int, 2> new_node_flag;
624  array<Edge, 2> intersect_edge;
625  array<Wall*, 4> div_wall {{nullptr, nullptr, nullptr, nullptr}};
626  array<double, 2> orig_length {{0.0, 0.0}};
627  array<double, 2> orig_rest_length {{0.0, 0.0}};
628  array<double, 2> orig_rest_length_init {{0.0, 0.0}};
629 
630  //--------------------------------------------------------------------------
631  // Preliminary: compute required info to effect the split: which edges are
632  // intersected, what are the intersection points, do the intersection
633  // points need to be coalesced with existing nodes because the are so
634  // close to them.
635  //--------------------------------------------------------------------------
636  ComputeIntersection(this_cell, intersect_nodes, from, to,
637  new_node_vector, new_node_ptr, new_node_flag, intersect_edge);
638 
639  //--------------------------------------------------------------------------
640  // For both edges that have an intersection on them: insert its new node
641  // into all cells that own the edge but only if it really is a new node.
642  // If the intersect is too close to an existing node, do nothing.
643  //--------------------------------------------------------------------------
644  for (int i = 0; i < 2; i++) {
645  Cell* neighbor_cell = m_mesh->FindEdgeNeighbor(this_cell, intersect_edge[i]);
646  assert(neighbor_cell != nullptr && "Where is the neighbor?");
647 
648  if (new_node_flag[i] == 0) {
649  new_node_ptr[i] = InsertNewNodeAtIntersect(
650  this_cell, neighbor_cell, new_node_vector[i], intersect_edge[i]);
651 
652  //--------------------------------------------------------------------------
653  // Update node ownership.
654  //--------------------------------------------------------------------------
655  m_mesh->UpdateNodeOwningNeighbors(neighbor_cell);
656 
657  //--------------------------------------------------------------------------
658  // If node is inserted into fixed edge (i.e. in the petiole)
659  // make the new node fixed as well.
660  //--------------------------------------------------------------------------
661  (new_node_ptr[i])->SetFixed(intersect_edge[i].IsFixed());
662  }
663 
664  AddSplitWalls(this_cell, neighbor_cell, i, new_node_ptr, div_wall, orig_length, orig_rest_length, orig_rest_length_init);
665 
666  }
667 
668  //--------------------------------------------------------------------------
669  // Bookkeeping for the nodes:
670  // 1) existing nodes need to be re-assigned from parent to the daughters.
671  // 2) add nodes of what will be the shared wall i.e those of the intersection
672  // plus intermediate ones along the wall if necessary
673  // 3) repair cell <-> node connectivities
674  //--------------------------------------------------------------------------
675  AssignExistingNodesToSplitCells(
676  m_mesh, this_cell, this_cell_nodes, daughter_nodes, new_node_ptr);
677  AddSharedWallNodes(
678  new_node_vector, new_node_ptr, this_cell_nodes, daughter_nodes);
679  m_mesh->UpdateNodeOwningNeighbors(this_cell);
680  m_mesh->UpdateNodeOwningNeighbors(daughter);
681 
682  //--------------------------------------------------------------------------
683  // Recalculate inertia integrals (this includes area)
684  //--------------------------------------------------------------------------
685  this_cell->SetGeoDirty();
686  daughter->SetGeoDirty();
687 
688  //--------------------------------------------------------------------------
689  // Bookkeeping for the walls:
690  // Existing walls need to reassigned and the cell <-> wall connectivity updated.
691  // The new wall between daughters is not included (need not be transferred).
692  //--------------------------------------------------------------------------
693  auto copy_walls = this_cell->GetWalls();
694  for (Wall* w : copy_walls) {
695  auto first = find(this_cell_nodes.begin(), this_cell_nodes.end(), w->GetN1());
696  auto second = find(this_cell_nodes.begin(), this_cell_nodes.end(), w->GetN2());
697 
698  if (first == this_cell_nodes.end() || second == this_cell_nodes.end()
699  || (w->GetN1() == new_node_ptr[0] && w->GetN2() == new_node_ptr[1])) {
700 
701  this_cell->ReassignWall(w, daughter);
702  if (w->GetC1() == this_cell) {
703  w->SetC1(daughter);
704  } else {
705  w->SetC2(daughter);
706  }
707  }
708  }
709 
710  //--------------------------------------------------------------------------
711  // Special case: a single cell is split. Single cells have no walls at all
712  // so we need to build the outer walls first.
713  //--------------------------------------------------------------------------
714  if (m_mesh->GetCells().size() == 2) {
715  Wall* daughter_wall = m_mesh->BuildWall(
716  new_node_ptr[0], new_node_ptr[1], daughter,
717  m_mesh->GetBoundaryPolygon());
718  daughter->AddWall(daughter_wall);
719  m_mesh->GetBoundaryPolygon()->AddWall(daughter_wall);
720  // Correct the walls associated with the nodes on the wall
721  m_mesh->UpdateNodeOwningWalls(daughter_wall);
722 
723  Wall* parent_wall = m_mesh->BuildWall(
724  new_node_ptr[1], new_node_ptr[0], this_cell,
725  m_mesh->GetBoundaryPolygon());
726  this_cell->AddWall(parent_wall);
727  m_mesh->GetBoundaryPolygon()->AddWall(parent_wall);
728  // Correct the walls associated with the nodes on the wall
729  m_mesh->UpdateNodeOwningWalls(parent_wall);
730  }
731 
732  //--------------------------------------------------------------------------
733  // Add the new wall shared by the daughter and to the necessary bookkeeping.
734  //--------------------------------------------------------------------------
735  auto wall = m_mesh->BuildWall(
736  new_node_ptr[0], new_node_ptr[1], this_cell, daughter);
737  this_cell->AddWall(wall);
738  daughter->AddWall(wall);
739  // Correct the walls associated with the nodes on the wall
740  m_mesh->UpdateNodeOwningWalls(wall);
741 
742  if ( m_model_name == "Wortel" ) {
743  double wall_strength = 0.0;
744  std::array<double, 3> ref{{1., 0., 0.}};
745  std::array<double, 3> tot1 = *wall->GetN1();
746  std::array<double, 3> tot2 = *wall->GetN2();
747  std::array<double, 3> tot3 = tot1 - tot2;
748  double t2 = SignedAngle(tot3, ref);
749  if ( ( t2 > (-pi() * 3 / 4) && t2 <= (-pi() / 4) ) || ( t2 > (pi() / 4) && t2 <= (pi() * 3 / 4) ) )
750  {
751  wall_strength = 1.;
752  } else {
753  wall_strength = 5.;//DDV: should be 1 for Blad, 5 for Wortel.
754  }
755  wall->SetStrength(wall_strength);
756  }
757 
758  //--------------------------------------------------------------------------
759  // Correct transporter concentrations of divided walls.
760  //--------------------------------------------------------------------------
761  for (int i = 0; i < 4; i++) {
762  if (div_wall[i]) {
763  const double current_length = div_wall[i]->GetLength();
764  const double correction = current_length / orig_length[i/2];
765 
766  div_wall[i]->SetRestLength(orig_rest_length[i/2] * correction);
767  div_wall[i]->SetRestLengthInit(orig_rest_length_init[i/2] * correction);
768 
769  auto transporters1 = div_wall[i]->GetTransporters1();
770  for (auto& t : transporters1) {
771  t *= correction;
772  }
773  div_wall[i]->SetTransporters1(transporters1);
774 
775  auto transporters2 = div_wall[i]->GetTransporters2();
776  for (auto& t : transporters2) {
777  t *= correction;
778  }
779  div_wall[i]->SetTransporters2(transporters2);
780  }
781  }
782 
783  //--------------------------------------------------------------------------
784  // Collect neighbors affected by this cell's division, namely
785  // this cell's old neighbors, this cell and the daughter.
786  //--------------------------------------------------------------------------
787  list<Cell*> broken_neighbors;
788  auto& this_neighbors = m_mesh->GetNeighbors(this_cell);
789  copy(this_neighbors.begin(), this_neighbors.end(), back_inserter(broken_neighbors));
790  broken_neighbors.push_back(this_cell);
791  broken_neighbors.push_back(daughter);
792 
793  //--------------------------------------------------------------------------
794  // Now reconstruct neighbor list for all "broken" neighbors.
795  //--------------------------------------------------------------------------
796  for (auto const& bn : broken_neighbors) {
797  m_mesh->ConstructNeighborList(bn);
798  }
799 
800  return daughter;
801 }
802 
803 } // namespace
Math constants.
Core data with mesh, parameters, random engine and time data.
Definition: CoreData.h:38
constexpr int signum(T x, std::false_type)
Overload for unsigned types.
Definition: signum.h:32
constexpr double small_real()
Small real number.
Definition: constants.h:35
STL namespace.
Interface for CellDivider.
A cell contains walls and nodes.
Definition: Cell.h:48
Node in cell wall.
Definition: Node.h:39
Core data used during model execution.
Plain data structure with cell geometric data (such as area).
Definition: GeoData.h:35
const std::list< Wall * > & GetWalls() const
Access the cell's walls.
Definition: Cell.h:88
Interface for NeighborNodes.
Interface of RandomEngine.
Extremely simple Exception root class.
Definition: Exception.h:28
Namespace for the core simulator.
An Edge connects two nodes and is ambidextrous.
Definition: Edge.h:31
Interface for Cell.
Namespace for container related classes.
void SetLengthDirty() const
Sets the 'dirty bit' i.e. length will recalculated on first use.
Definition: Wall.h:131
Macro defs for debug and logging.
Structure of neighboring nodes: two neighboring nodes from standpoint of a given cell with an orderin...
Definition: NeighborNodes.h:34
Proxy for dealing with the factories.
Node * GetFirst() const
Get the first node of the edge.
Definition: Edge.h:45
const std::vector< Node * > & GetNodes() const
Access the nodes of cell's polygon.
Definition: Cell.h:79
Interface for Node.
ConstCircularIterator class and helper functions.
int GetIndex() const
Return the index.
Definition: Cell.h:76
std::list< NeighborNodes > & GetNodeOwningNeighbors(Node *n)
Get the neighbors associated with this node.
Definition: Mesh.h:124
std::array< double, 3 > GetCentroid() const
Return the centroid position.
Definition: Cell.cpp:205
Interface for Edge.
Attributes of Cell.
Interface for Geom.
Extending std with arithmetic for std::array.
Structure of cells; key data structure.
Definition: Mesh.h:62
std::tuple< double, std::array< double, 3 >, double > GetEllipseAxes() const
Calculate axes (length and direction) area moment of inertia ellipse.
Definition: GeoData.h:50
GeoData GetGeoData() const
Return GeData (area, centroid, area moment of inertia).
Definition: Cell.cpp:225
CircularIterator< T > next(CircularIterator< T > i)
Helper yields the position the iterator would have if moved forward (in circular fashion) by 1 positi...
Interface for CellAttributes.
Header file for Exception class.
ConstCircularIterator< typename T::const_iterator > make_const_circular(const T &c)
Helper produces const circular iterator whose range corresponds to the begin and end iterators of a c...
CircularIterator< T > prev(CircularIterator< T > i)
Helper yields the position the iterator would have if moved backward (in circular fashion) by 1 posit...
CircularIterator class and helper functions.
constexpr double pi()
Math constant pi.
Definition: constants.h:29
A cell wall, runs between cell corner points and consists of wall elements.
Definition: Wall.h:48
bool Check() const
Verify all pointers non-null.
Definition: CoreData.h:53
Node * GetSecond() const
Get the second node of the edge.
Definition: Edge.h:51
Interface for Wall.
Interface for Mesh.