VPTissue Reference Manual
Mesh.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  */
20 #include "Mesh.h"
21 
22 #include "Cell.h"
23 #include "BoundaryType.h"
24 #include "Edge.h"
25 #include "MeshState.h"
26 #include "Node.h"
27 #include "WallType.h"
28 
30 #include "util/misc/Exception.h"
31 #include "util/misc/log_debug.h"
32 
33 #include <boost/property_tree/ptree.hpp>
34 #include <boost/lexical_cast.hpp>
35 #include <boost/optional.hpp>
36 
37 #include <algorithm>
38 #include <array>
39 #include <cmath>
40 #include <functional>
41 #include <iomanip>
42 #include <ios>
43 #include <iostream>
44 #include <iterator>
45 #include <list>
46 #include <memory>
47 #include <set>
48 #include <sstream>
49 #include <string>
50 #include <tuple>
51 #include <vector>
52 
53 using namespace boost::property_tree;
54 using boost::optional;
55 using boost::lexical_cast;
56 using namespace std;
57 using namespace SimPT_Sim;
58 using namespace SimPT_Sim::Container;
59 using namespace SimPT_Sim::Util;
60 
61 namespace SimPT_Sim {
62 
63 namespace {
64  struct null_deleter {
65  void operator()(const void*) {}
66  };
67 }
68 
69 Mesh::Mesh(unsigned int num_chemicals)
70  : m_boundary_polygon(nullptr),
71  m_cell_next_id(0),
72  m_node_next_id(0),
73  m_num_chemicals(num_chemicals),
74  m_wall_next_id(0)
75 {
76 }
77 
78 void Mesh::AddConsecutiveNodeToCell(Cell* c, Node* n, Node* nb1, Node* nb2)
79 {
80  c->GetNodes().push_back(n);
81  GetNodeOwningNeighbors(n).push_back(NeighborNodes(c, nb1, nb2));
82 }
83 
84 void Mesh::AddNodeToCell(Cell* c, Node* n, Node* nb1, Node* nb2)
85 {
86  assert(std::find(c->GetNodes().begin(), c->GetNodes().end(), nb1) != c->GetNodes().end() && "Neighbor 1 not present in cell!");
87  assert(std::find(c->GetNodes().begin(), c->GetNodes().end(), nb2) != c->GetNodes().end() && "Neighbor 2 not present in cell!");
88 
89  auto ins_pos = find(c->GetNodes().begin(), c->GetNodes().end(), nb1);
90 
91  // ... second node comes before or after it ...
92  if (*(++ins_pos != c->GetNodes().end() ? ins_pos : c->GetNodes().begin()) != nb2) {
93  c->GetNodes().insert(
94  ((ins_pos--) != c->GetNodes().begin() ?
95  ins_pos : (--c->GetNodes().end())),
96  n);
97  //cells[c->cell].nodes.insert(--ins_pos, new_node->index);
98  // .. set the neighbors of the new node ...
99  // in this case e.second and e.first are inverted
100  GetNodeOwningNeighbors(n).push_back(
101  NeighborNodes(c, nb2, nb1));
102  } else {
103  // insert before second node, so leave ins_pos as it is, that is incremented
104  c->GetNodes().insert(ins_pos, n);
105  // .. set the neighbors of the new node ...
106  GetNodeOwningNeighbors(n).push_back(
107  NeighborNodes(c, nb1, nb2));
108  }
109 
110  // Lambda to test cell index equality
111  auto is_nb = [c](const NeighborNodes& n) {
112  return (n.GetCell()->GetIndex() == c->GetIndex());
113  };
114 
115  // Find cell c in NeighborNodes owners of Node edge.first and correct the record
116  {
117  auto& own = GetNodeOwningNeighbors(nb1);
118  const auto cpos = find_if(own.begin(), own.end(), is_nb);
119  if (cpos->GetNb1() == nb2) {
120  const NeighborNodes tmp(cpos->GetCell(), n, cpos->GetNb2());
121  *cpos = tmp;
122  } else if (cpos->GetNb2() == nb2) {
123  const NeighborNodes tmp(cpos->GetCell(), cpos->GetNb1(), n);
124  *cpos = tmp;
125  }
126  }
127 
128  // Same for Node edge.second
129  {
130  auto& own = GetNodeOwningNeighbors(nb2);
131  const auto cpos = find_if(own.begin(), own.end(), is_nb);
132  if (cpos->GetNb1() == nb1) {
133  const NeighborNodes tmp(cpos->GetCell(), n, cpos->GetNb2());
134  *cpos = tmp;
135  } else if (cpos->GetNb2() == nb1) {
136  const NeighborNodes tmp(cpos->GetCell(), cpos->GetNb1(), n);
137  *cpos = tmp;
138  }
139  }
140 }
141 
142 Cell* Mesh::BuildBoundaryPolygon(const vector<unsigned int>& node_ids)
143 {
144  auto new_cell = m_cell_storage.emplace_back(-1, GetNumChemicals());
145  //m_boundary_polygon = Cell*(new_cell, null_deleter());
146  m_boundary_polygon = new_cell;
147 
148  unsigned int const nnodes = node_ids.size();
149  for (unsigned int i = 0; i < nnodes; i++) {
150  assert((GetNodes()[node_ids[i]] != nullptr) && "Node has to exist already!");
151  assert((GetNodes()[node_ids[(nnodes + i - 1) % nnodes]] != nullptr) && "Node has to exist already!");
152  assert((GetNodes()[node_ids[(i + 1) % nnodes]] != nullptr) && "Node has to exist already!");
153  AddConsecutiveNodeToCell(m_boundary_polygon, GetNodes()[node_ids[i]],
154  GetNodes()[node_ids[(nnodes + i - 1) % nnodes]],
155  GetNodes()[node_ids[(i + 1) % nnodes]]);
156  }
157 
158  return m_boundary_polygon;
159 }
160 
161 Cell* Mesh::BuildCell()
162 {
163  auto new_cell = m_cell_storage.emplace_back(m_cell_next_id++, GetNumChemicals());
164  //auto c = Cell*(new_cell, null_deleter());
165  auto c = new_cell;
166  m_cells.push_back(c);
167  return c;
168 }
169 
170 Cell* Mesh::BuildCell(const std::vector<unsigned int>& node_ids)
171 {
172  return BuildCell(m_cell_next_id, node_ids);
173 }
174 
175 Cell* Mesh::BuildCell(unsigned int id, const vector<unsigned int>& node_ids)
176 {
177  assert((id >= m_cell_next_id) && "Cell id not increasing!");
178  auto new_cell = m_cell_storage.emplace_back(id++, GetNumChemicals());
179  //auto c = Cell*(new_cell, null_deleter());
180  auto c = new_cell;
181  m_cell_next_id = max(m_cell_next_id, id);
182  m_cells.push_back(c);
183 
184  unsigned int const nnodes = node_ids.size();
185  for (unsigned int i = 0; i < nnodes; i++) {
186  assert((GetNodes()[node_ids[i]] != nullptr) && "Node has to exist already!");
187  assert((GetNodes()[node_ids[(nnodes + i - 1) % nnodes]] != nullptr) && "Node has to exist already!");
188  assert((GetNodes()[node_ids[(i + 1) % nnodes]] != nullptr) && "Node has to exist already!");
189  AddConsecutiveNodeToCell(c, GetNodes()[node_ids[i]],
190  GetNodes()[node_ids[(nnodes + i - 1) % nnodes]],
191  GetNodes()[node_ids[(i + 1) % nnodes]]);
192  }
193 
194  return c;
195 }
196 
197 Node* Mesh::BuildNode(const array<double, 3>& vec, bool at_boundary)
198 {
199  auto new_node = m_node_storage.emplace_back(m_node_next_id++, vec, at_boundary);
200  //auto n = Node*(new_node, null_deleter());
201  auto n = new_node;
202  m_nodes.push_back(n);
203  return n;
204 }
205 
206 Node* Mesh::BuildNode(unsigned int id, const array<double, 3>& vec, bool at_boundary)
207 {
208  assert((id >= m_node_next_id) && "Node id not increasing!");
209  auto new_node = m_node_storage.emplace_back(id++, vec, at_boundary);
210  //auto n = Node*(new_node, null_deleter());
211  auto n = new_node;
212  m_node_next_id = max(m_node_next_id, id);
213  m_nodes.push_back(n);
214  return n;
215 }
216 
217 Wall* Mesh::BuildWall(Node* n1, Node* n2, Cell* c1, Cell* c2)
218 {
219  assert( (n1 != nullptr) && "Wall::Wall> Attempting to build a wall with nullptr node!" );
220  assert( (n2 != nullptr) && "Wall::Wall> Attempting to build a wall with nullptr node!" );
221  assert( (c1 != nullptr) && "Wall::Wall> Attempting to build a wall with nullptr cell!" );
222  assert( (c2 != nullptr) && "Wall::Wall> Attempting to build a wall with nullptr cell!" );
223  assert( (n1 != n2) && "Wall::Wall> Attempting to build a wall between identical nodes!" );
224  assert( (c1 != c2) && "Wall::Wall> Attempting to build a wall between identical cells!" );
225  //if ( m_model_name != "Wortel" ){};//DDV
226  auto new_wall = m_wall_storage.emplace_back(m_wall_next_id++, n1, n2, c1, c2, GetNumChemicals()/*,isWortel*/);
227  //auto wall = Wall*(new_wall, null_deleter());
228  auto wall = new_wall;
229  m_walls.push_back(wall);
230 
231  return wall;
232 }
233 
234 Wall* Mesh::BuildWall(unsigned int id, Node* n1, Node* n2, Cell* c1, Cell* c2)
235 {
236  assert( (n1 != nullptr) && "Wall::Wall> Attempting to build a wall with nullptr node!" );
237  assert( (n2 != nullptr) && "Wall::Wall> Attempting to build a wall with nullptr node!" );
238  assert( (c1 != nullptr) && "Wall::Wall> Attempting to build a wall with nullptr cell!" );
239  assert( (c2 != nullptr) && "Wall::Wall> Attempting to build a wall with nullptr cell!" );
240  assert( (n1 != n2) && "Wall::Wall> Attempting to build a wall between identical nodes!" );
241  assert( (c1 != c2) && "Wall::Wall> Attempting to build a wall between identical cells!" );
242  //As above...
243  auto new_wall = m_wall_storage.emplace_back(id++, n1, n2, c1, c2, GetNumChemicals()/*,*/);
244  //auto wall = Wall*(new_wall, null_deleter());
245  auto wall = new_wall;
246  m_wall_next_id = max(m_wall_next_id, id);
247  m_walls.push_back(wall);
248 
249  return wall;
250 }
251 
253 {
254  list<Cell*>& neighbors = m_wall_neighbors[cell];
255  neighbors.clear();
256 
257  const list<Wall*>& walls = cell->GetWalls();
258  for (auto const& wall : walls) {
259  if (wall->GetC1() != cell && !wall->GetC1()->IsBoundaryPolygon()) {
260  neighbors.push_back(wall->GetC1());
261  } else if (wall->GetC2() != cell && !wall->GetC2()->IsBoundaryPolygon()) {
262  neighbors.push_back(wall->GetC2());
263  }
264  }
265 }
266 
268 {
269  Cell* neighbor_cell = nullptr;
270 
271  // Push all cells owning the two nodes of the divides edges onto a list
272  list<NeighborNodes> owners;
273  auto& owners_first = GetNodeOwningNeighbors(edge.GetFirst());
274  copy(owners_first.begin(), owners_first.end(), back_inserter(owners));
275  auto& owners_second = GetNodeOwningNeighbors(edge.GetSecond());
276  copy(owners_second.begin(), owners_second.end(), back_inserter(owners));
277 
278  // Lambdas to compare neighbors.
279  auto cmp = [](const NeighborNodes& n1, const NeighborNodes& n2) {
280  return n1.GetCell()->GetIndex() < n2.GetCell()->GetIndex();
281  };
282  auto eql = [](const NeighborNodes& n1, const NeighborNodes& n2) {
283  return n1.GetCell()->GetIndex() == n2.GetCell()->GetIndex();
284  };
285 
286  // Find first non-self duplicate in the owners:
287  // cells owning the same two nodes share an edge with me
288  owners.sort(cmp);
289  list<NeighborNodes>::iterator it;
290  for (it = owners.begin(); it != owners.end(); ++it) {
291  it = adjacent_find(it, owners.end(), eql);
292  if (it == owners.end()) {
293  break; // bail if reach the end of the list
294  }
295  if (it->GetCell()->GetIndex() != cell->GetIndex()) {
296  // This is necessary because two endpoints can have more than two similar cells neighbors.
297  // For example:
298  //
299  // 1---2---3---4
300  // | |___| |
301  // |___________|
302  //
303  // 2 and 3 have three cell neighbors the same.
304 
305  bool isCorrectNeighbor = false;
306 
307  auto cit = make_const_circular(it->GetCell()->GetNodes());
308  do {
309  if (Edge(*cit, *next(cit)) == edge) {
310  isCorrectNeighbor = true;
311  }
312  } while (!isCorrectNeighbor && ++cit != it->GetCell()->GetNodes().begin());
313 
314  if (isCorrectNeighbor) {
315  neighbor_cell = it->GetCell();
316  break;
317  }
318  }
319  }
320  assert((neighbor_cell != nullptr) && "There has to be a neighbor");
321  return neighbor_cell;
322 
323  //TODO: This doesn't always work (see above why.)
324 
325  /*Cell* neighbor_cell = nullptr;
326 
327  // Push all cells owning the two nodes of the divides edges onto a list
328  list<Neighbor> owners;
329  auto& owners_first = GetNodeOwningNeighbors(edge.GetFirst());
330  copy(owners_first.begin(), owners_first.end(), back_inserter(owners));
331  auto& owners_second = GetNodeOwningNeighbors(edge.GetSecond());
332  copy(owners_second.begin(), owners_second.end(), back_inserter(owners));
333 
334  // Lambdas to compare neighbors.
335  auto cmp = [](const Neighbor& n1, const Neighbor& n2) {
336  return n1.GetCell()->GetIndex() < n2.GetCell()->GetIndex();
337  };
338  auto eql = [](const Neighbor& n1, const Neighbor& n2) {
339  return n1.GetCell()->GetIndex() == n2.GetCell()->GetIndex();
340  };
341 
342  // Find first non-self duplicate in the owners:
343  // cells owning the same two nodes share an edge with me
344  owners.sort(cmp);
345  list<Neighbor>::iterator it;
346  for (it = owners.begin(); it != owners.end(); it++) {
347  it = adjacent_find(it, owners.end(), eql);
348  if (it == owners.end()) {
349  break; // bail if reach the end of the list
350  }
351  if (it->GetCell()->GetIndex() != cell->GetIndex()) {
352  neighbor_cell = it->GetCell();
353  break;
354  }
355  }
356  assert((neighbor_cell != nullptr) && "There has to be a neighbor");
357  return neighbor_cell;
358  */
359 }
360 
361 Node* Mesh::FindNextBoundaryNode(Node* boundary_node) const
362 {
363  auto current = find(m_boundary_polygon->GetNodes().begin(),
364  m_boundary_polygon->GetNodes().end(), boundary_node);
365  if (current != m_boundary_polygon->GetNodes().end()) {
366  return (++current != m_boundary_polygon->GetNodes().end())
367  ? *current : *m_boundary_polygon->GetNodes().begin();
368  } else {
369  return nullptr;
370  }
371 }
372 
373 Wall* Mesh::FindWall(const Edge& edge) const
374 {
375  if (m_walls.empty()) {
376  assert(m_cells.size() == 1 && "The only case without walls in mesh, is single cell.");
377  return nullptr;
378  }
379 
380  auto neighbors = GetEdgeOwners(edge); // neighbors == [C1, C1, C2, C2].
381  Cell* cell1 = neighbors.front().GetCell();
382  Cell* cell2 = neighbors.back().GetCell();
383 
384  //Lambda to check whether the given wall doesn't contain both cell1 and cell2.
385  auto not_contain_cells = [cell1, cell2](Wall* w){
386  return (w->GetC1() != cell1 && w->GetC2() != cell1)
387  || (w->GetC1() != cell2 && w->GetC2() != cell2);
388  };
389 
390  auto walls = cell1->GetWalls();
391  walls.remove_if(not_contain_cells);
392  assert(!walls.empty() && "At least one candidate wall tshould associated with the edge.");
393 
394  for (auto w : walls) {
395  auto cellNodes = w->GetC1()->GetNodes();
396  rotate(cellNodes.begin(), find(cellNodes.begin(),
397  cellNodes.end(), w->GetN1()), cellNodes.end());
398 
399  for (auto it = cellNodes.begin(); it != find(cellNodes.begin(), cellNodes.end(), w->GetN2()); it++) {
400  if ((edge.GetFirst() == *it && edge.GetSecond() == *next(it))
401  || (edge.GetSecond() == *it && edge.GetFirst() == *next(it))) {
402 
403  return w;
404  }
405  }
406  }
407  assert(false && "No wall has been found for the given edge.");
408 
409  return nullptr;
410 }
411 
412 void Mesh::FixCellIDs()
413 {
414  auto cmp = [](Cell* c1, Cell* c2) {
415  return c1->GetIndex() < c2->GetIndex();
416  };
417 
418  sort(m_cells.begin(), m_cells.end(), cmp);
419  for (unsigned int i = 0; i < m_cells.size(); i++) {
420  m_cells[i]->m_index = i;
421  }
422 
423  m_cell_next_id = m_cells.size();
424 }
425 
426 void Mesh::FixNodeIDs()
427 {
428  auto cmp = [](Node* n1, Node* n2) {
429  return n1->GetIndex() < n2->GetIndex();
430  };
431 
432  sort(m_nodes.begin(), m_nodes.end(), cmp);
433  for (unsigned int i = 0; i < m_nodes.size(); i++) {
434  m_nodes[i]->m_index = i;
435  }
436 
437  m_node_next_id = m_nodes.size();
438 }
439 
440 void Mesh::FixWallIDs()
441 {
442  auto cmp = [](Wall* w1, Wall* w2) {
443  return w1->GetIndex() < w2->GetIndex();
444  };
445 
446  sort(m_walls.begin(), m_walls.end(),cmp);
447  unsigned int i = 0;
448  for (auto wall : m_walls) {
449  wall->m_wall_index = i++;
450  }
451 
452  m_wall_next_id = m_walls.size();
453 }
454 
455 vector<NeighborNodes> Mesh::GetEdgeOwners(const Edge& edge) const
456 {
457  list<NeighborNodes> owners;
458 
459  // Lambdas to sort and test-equal NeighborNodes.
460  auto cmp = [](const NeighborNodes& n1, const NeighborNodes& n2) {
461  return n1.GetCell()->GetIndex() < n2.GetCell()->GetIndex();
462  };
463  auto eql = [](const NeighborNodes& n1, const NeighborNodes& n2) {
464  return n1.GetCell()->GetIndex() == n2.GetCell()->GetIndex();
465  };
466 
467  // Push all cells owning either of the two nodes of the edge onto a list.
468  auto& owners_first = GetNodeOwningNeighbors(edge.GetFirst());
469  copy(owners_first.begin(), owners_first.end(), back_inserter(owners));
470  auto& owners_second = GetNodeOwningNeighbors(edge.GetSecond());
471  copy(owners_second.begin(), owners_second.end(), back_inserter(owners));
472  owners.sort(cmp);
473 
474  // The duplicates in this list indicate cells owning both nodes.
475  vector<NeighborNodes> edge_owners;
476  auto n = adjacent_find(owners.begin(), owners.end(), eql);
477  while (n != owners.end()) {
478  const auto owner_a = *n;
479  const auto owner_b = *(++n);
480  const Edge e1(owner_a.GetNb1(), owner_b.GetNb2());
481  const Edge e2(owner_b.GetNb1(), owner_a.GetNb2());
482  if ( e1 == edge || e2 == edge ) {
483  edge_owners.push_back(owner_a);
484  edge_owners.push_back(owner_b);
485  }
486  n = adjacent_find(n, owners.end(), eql);
487  }
488 
489  assert(edge_owners.size() == 4 && "An edge can only have two neighboring cells per endpoint.");
490 
491  return edge_owners;
492 }
493 
495 {
496  MeshState state;
497  try {
498  // Nodes
499  state.SetNumNodes(m_nodes.size());
500  state.NodeAttributeContainer().Add<int>("fixed");
501  state.NodeAttributeContainer().Add<int>("sam");
502  state.NodeAttributeContainer().Add<int>("boundary");
503  size_t node_idx = 0;
504  for (auto const& n : m_nodes) {
505  state.SetNodeID(node_idx, n->GetIndex());
506  state.SetNodeX(node_idx, (*n)[0]);
507  state.SetNodeY(node_idx, (*n)[1]);
508  state.NodeAttributeContainer().Set<int>(node_idx, "fixed", n->IsFixed());
509  state.NodeAttributeContainer().Set<int>(node_idx, "sam", n->IsSam());
510  state.NodeAttributeContainer().Set<int>(node_idx, "boundary", n->IsAtBoundary());
511  ++node_idx;
512  }
513 
514  // Cells
515  state.SetNumCells(m_cells.size());
516  state.CellAttributeContainer().Add<int>("type");
517  state.CellAttributeContainer().Add<double>("area");
518  state.CellAttributeContainer().Add<double>("solute");
519  state.CellAttributeContainer().Add<double>("target_area");
520  state.CellAttributeContainer().Add<double>("target_length");
521  state.CellAttributeContainer().Add<int>("dead");
522  state.CellAttributeContainer().Add<int>("div_counter");
523  state.CellAttributeContainer().Add<double>("stiffness");
524  state.CellAttributeContainer().Add<string>("boundary_type");
525  state.CellAttributeContainer().Add<int>("fixed");
526  // TODO: a bunch of other attributes: cfr. CellAttributes
527  // Cell chemicals are attributes as well
528  for (size_t chem_idx = 0; chem_idx < GetNumChemicals(); ++chem_idx) {
529  state.CellAttributeContainer().Add<double>("chem_" + lexical_cast<string>(chem_idx));
530  }
531  size_t cell_idx = 0;
532  for (auto c : m_cells) {
533  // IDs of cells
534  state.SetCellID(cell_idx, c->GetIndex());
535  // Loop over cell's nodes and collect their indices
536  vector<int> cell_nodes;
537  for (auto const& node : c->GetNodes()) {
538  cell_nodes.push_back(node->GetIndex());
539  }
540  state.SetCellNodes(cell_idx, cell_nodes);
541  // Loop over cell's walls and collect their indices
542  vector<int> cell_walls;
543  for (auto const& wall : c->GetWalls()) {
544  cell_walls.push_back(wall->GetIndex());
545  }
546  state.SetCellWalls(cell_idx, cell_walls);
547  // Collect cell attributes
548  state.CellAttributeContainer().Set<int>(
549  cell_idx, "type", c->GetCellType());
550  state.CellAttributeContainer().Set<double>(
551  cell_idx, "area", c->GetArea());
552  state.CellAttributeContainer().Set<double>(
553  cell_idx, "solute", c->GetSolute());
554  state.CellAttributeContainer().Set<double>(
555  cell_idx, "target_area", c->GetTargetArea());
556  state.CellAttributeContainer().Set<double>(
557  cell_idx, "target_length", c->GetTargetLength());
558  state.CellAttributeContainer().Set<int>(
559  cell_idx, "dead", c->IsDead());
560  state.CellAttributeContainer().Set<int>(
561  cell_idx, "div_counter", c->GetDivisionCounter());
562  state.CellAttributeContainer().Set<double>(
563  cell_idx, "stiffness", c->GetStiffness());
564  state.CellAttributeContainer().Set<string>(
565  cell_idx, "boundary_type", ToString(c->GetBoundaryType()));
566  state.CellAttributeContainer().Set<int>(
567  cell_idx, "fixed", c->IsFixed());
568  for (size_t chem_idx = 0; chem_idx < GetNumChemicals(); ++chem_idx) {
569  state.CellAttributeContainer().Set<double>(
570  cell_idx, "chem_" + lexical_cast<string>(chem_idx),
571  c->GetChemical(chem_idx));
572  }
573  ++cell_idx;
574  }
575 
576  // Boundary polygon: is a cell with ID = -1 but is stored separately in MeshState
577  vector<int> bp_nodes;
578  for (auto const& node : m_boundary_polygon->GetNodes()) {
579  bp_nodes.push_back(node->GetIndex());
580  }
581  state.SetBoundaryPolygonNodes(bp_nodes);
582  vector<int> bp_walls;
583  for (auto const& wall : m_boundary_polygon->GetWalls()) {
584  bp_walls.push_back(wall->GetIndex());
585  }
586  state.SetBoundaryPolygonWalls(bp_walls);
587 
588  // The walls
589  state.SetNumWalls(m_walls.size());
590  state.WallAttributeContainer().Add<double>("length");
591  state.WallAttributeContainer().Add<double>("rest_length");
592  state.WallAttributeContainer().Add<double>("rest_length_init");
593  state.WallAttributeContainer().Add<double>("strength");
594  state.WallAttributeContainer().Add<string>("type");
595  // Wall transporters are attributes as well
596  for (size_t chem_idx = 0; chem_idx < GetNumChemicals(); ++chem_idx) {
597  state.WallAttributeContainer().Add<double>(
598  "trans_1_chem_" + lexical_cast<string>(chem_idx));
599  state.WallAttributeContainer().Add<double>(
600  "trans_2_chem_" + lexical_cast<string>(chem_idx));
601  }
602  size_t wall_idx = 0;
603  for (auto const& w : m_walls) {
604  // IDs of walls
605  state.SetWallID(wall_idx, w->GetIndex());
606  // Connected cells and end nodes
607  state.SetWallNodes(wall_idx, make_pair(w->GetN1()->GetIndex(), w->GetN2()->GetIndex()));
608  state.SetWallCells(wall_idx, make_pair(w->GetC1()->GetIndex(), w->GetC2()->GetIndex()));
609  // Collect wall attributes
610  state.WallAttributeContainer().Set<double>(
611  wall_idx, "length", w->GetLength());
612  state.WallAttributeContainer().Set<double>(
613  wall_idx, "rest_length", w->GetRestLength());
614  state.WallAttributeContainer().Set<double>(
615  wall_idx, "rest_length_init", w->GetRestLengthInit());
616  state.WallAttributeContainer().Set<double>(
617  wall_idx, "strength", w->GetStrength());
618  state.WallAttributeContainer().Set<string>(
619  wall_idx, "type", WallType::ToString(w->GetType()));
620  for (size_t chem_idx = 0; chem_idx < GetNumChemicals(); ++chem_idx) {
621  state.WallAttributeContainer().Set<double>(
622  wall_idx, "trans_1_chem_" + lexical_cast<string>(chem_idx),
623  w->GetTransporters1(chem_idx));
624  state.WallAttributeContainer().Set<double>(
625  wall_idx, "trans_2_chem_" + lexical_cast<string>(chem_idx),
626  w->GetTransporters2(chem_idx));
627  }
628  ++wall_idx;
629  }
630  } catch (exception& e) {
631  cout << "ERROR in Mesh::GetState(): " << e.what() << endl;
632  }
633  return state;
634 }
635 
636 bool Mesh::IsAtBoundary(const Edge* e) const
637 {
638  if (e->GetFirst()->IsAtBoundary() && e->GetSecond()->IsAtBoundary()) {
639  auto node1 = FindNextBoundaryNode(e->GetFirst());
640  auto node2 = FindNextBoundaryNode(e->GetSecond());
641  return node1 == e->GetSecond() || node2 == e->GetFirst();
642  }
643  else {
644  return false;
645  }
646 }
647 
648 bool Mesh::IsAtBoundary(Wall* w) const
649 {
650  bool status = false;
651  if (w->GetC1() == m_boundary_polygon || w->GetC2() == m_boundary_polygon) {
652  status = true;
653  }
654  return status;
655 }
656 
658 {
659  bool status = false;
660  const auto& bp_nodes = m_boundary_polygon->GetNodes();
661  auto it = find(bp_nodes.begin(), bp_nodes.end(), n);
662  if (it != bp_nodes.end()) {
663  status = true;
664  }
665  return status;
666 }
667 
668 ostream& Mesh::Print(ostream& os) const {
669  static int i = 0;
670  i++;
671  os << "MESH_PRINT_" << i << endl;
672  os << "BOUNDARY_CELL" << endl;
673  if (m_boundary_polygon) {
674  m_boundary_polygon->Print(os) << endl;
675  }
676  os << "CELLS" << endl;
677  for (auto& cell : m_cells) {
678  cell->Print(os) << endl;
679  }
680  os << "NODES" << endl;
681  for (auto& node : m_nodes) {
682  node->Print(os) << endl;
683  }
684  os << "WALLS" << endl;
685  for (auto& wall : m_walls) {
686  wall->Print(os) << endl;
687  }
688  os << "NODE_AND_ITS_NEIGHBOR_NODES" << endl;
689  {
690  set<string> ordered_output;
691  ostringstream os;
692  for (auto& pair : m_node_owning_neighbors) {
693  os.str("");
694  os << "=====NODE=====" << endl;
695  pair.first->Print(os) << endl;
696  for (auto& n : pair.second) {
697  os << "-----here-comes-an-entry-----" << endl;
698  os << "***CELL: " << endl;
699  n.GetCell()->Print(os) << endl;
700  os << "***NB_1: " << endl;
701  n.GetNb1()->Print(os) << endl;
702  os << "***NB_2: " << endl;
703  os << "-----------------------------" << endl;
704  n.GetNb2()->Print(os) << endl;
705  }
706  os << "==============" << endl;
707  ordered_output.insert(os.str());
708  }
709  for (string s : ordered_output) {
710  os << s;
711  }
712  }
713  os << "NODE_AND_ITS_WALLS" << endl;
714  {
715  set<string> ordered_output;
716  ostringstream os;
717  for (auto& pair : m_node_owning_walls) {
718  os.str("");
719  os << "=====NODE=====" << endl;
720  pair.first->Print(os) << endl;
721  for (auto& wall : pair.second) {
722  os << "-----here-comes-an-entry-----" << endl;
723  os << "***WALL: " << endl;
724  wall->Print(os) << endl;
725  os << "-----------------------------" << endl;
726  }
727  os << "==============" << endl;
728  ordered_output.insert(os.str());
729  }
730  for (string s : ordered_output) {
731  os << s;
732  }
733  }
734  os << "CELL_AND_ITS_NEIGHBOR_CELLS_HAVING_A_COMMON_WALL" << endl;
735  {
736  set<string> ordered_output;
737  ostringstream os;
738  for (auto& pair: m_wall_neighbors) {
739  os.str("");
740  os << "=====CELL=====" << endl;
741  pair.first->Print(os) << endl;
742  for (auto& cell: pair.second) {
743  os << "-----here-comes-an-entry-----" << endl;
744  os << "***NBCELL: " << endl;
745  cell->Print(os) << endl;
746  os << "-----------------------------" << endl;
747  }
748  os << "==============" << endl;
749  ordered_output.insert(os.str());
750  }
751  for (string s : ordered_output) {
752  os << s;
753  }
754  }
755  return os;
756 }
757 
759 {
760  m_wall_neighbors.erase(cell);
761 }
762 
764 {
765  m_node_owning_neighbors.erase(node);
766  m_node_owning_walls.erase(node);
767 }
768 
769 ptree Mesh::ToPtree() const
770 {
771  // ------------------------- File intro ---------------------------------
772  ptree ret_pt;
773 
774  // --------------- Cells & BoundaryPolygon ------------------------------
775  auto const& cells = GetCells();
776  ptree cells_pt;
777  cells_pt.put("count", cells.size());
778  cells_pt.put("chemical_count", GetNumChemicals());
779  for (auto const& cell : cells) {
780  cells_pt.add_child("cell_array.cell", cell->ToPtree());
781  }
782  cells_pt.put_child("boundary_polygon", GetBoundaryPolygon()->ToPtree());
783  ret_pt.put_child("cells", cells_pt);
784 
785  // --------------------------- Nodes ------------------------------------
786  const auto& nodes = GetNodes();
787  ptree nodes_pt;
788  nodes_pt.put("count", nodes.size());
789  for (const auto& node : nodes) {
790  nodes_pt.add_child("node_array.node", node->ToPtree());
791  }
792  ret_pt.put_child("nodes", nodes_pt);
793 
794  // --------------------------- Walls ----------------------------------
795  const auto& walls = GetWalls();
796  ptree walls_pt;
797  walls_pt.put("count", walls.size());
798  for (auto const& w : walls) {
799  walls_pt.add_child("wall_array.wall", w->ToPtree());
800  }
801  ret_pt.put_child("walls", walls_pt);
802 
803  return ret_pt;
804 }
805 
807 {
808  auto& nodes = cell->GetNodes();
809  if (!nodes.empty()) {
810  auto it = make_circular(nodes);
811  do {
812  auto& owners = GetNodeOwningNeighbors(*it);
813  // Clean existing connections in which this cell participates
814  if (owners.size() > 0) {
815  // remove myself from the neighbor list of the node
816  auto is_nb = [cell](const NeighborNodes& n) {
817  return (n.GetCell()->GetIndex() == cell->GetIndex());
818  };
819  auto nb_it = find_if(owners.begin(), owners.end(), is_nb);
820  if (nb_it != owners.end()) {
821  owners.erase(nb_it);
822  }
823  }
824  owners.push_back(NeighborNodes(cell, *prev(it), *next(it)));
825  } while (++it != nodes.begin());
826  }
827 }
828 
830 {
831  auto& nodes = wall->GetC1()->GetNodes();
832  auto start = find(nodes.begin(), nodes.end(), wall->GetN1());
833  auto stop = find(nodes.begin(), nodes.end(), wall->GetN2());
834  assert(start != nodes.end() && "N1 not found in C1 node list");
835  assert(stop != nodes.end() && "N2 not found in C1 node list");
836 
837  for (auto &endpoint : {start, stop}) {
838  auto &walls = m_node_owning_walls[*endpoint];
839  walls.remove_if([endpoint] (Wall *owningWall) { return owningWall->GetN1() != *endpoint && owningWall->GetN2() != *endpoint; } );
840  if (std::find(walls.begin(), walls.end(), wall) == walls.end()) {
841  walls.push_back(wall);
842  }
843  }
844 
845  auto cit = make_circular(nodes, start);
846  while (++cit != stop) {
847  m_node_owning_walls[*cit] = { wall }; // Nodes on the wall that are not the endpoints cannot be part of multiple walls
848  }
849 }
850 
851 }
void SetNodeY(size_t node_idx, double value)
Sets the y coordinate of a particular node.
Definition: MeshState.cpp:80
Cell * FindEdgeNeighbor(Cell *cell, Edge edge) const
Find the neighbor to this cell with respect to the given edge.
Definition: Mesh.cpp:267
bool IsAtBoundary(const Edge *e) const
True iff the edge is on the mesh boundary.
Definition: Mesh.cpp:636
STL namespace.
A cell contains walls and nodes.
Definition: Cell.h:48
void RemoveNodeFromOwnerLists(Node *node)
Removes the node from the 'node owning neighbors' and 'node owning walls' lists.
Definition: Mesh.cpp:763
Node in cell wall.
Definition: Node.h:39
Cell * GetCell() const
Return the cell of this Neighbor pair.
Interface of MeshState.
Namespace for miscellaneous utilities.
Definition: PTreeFile.cpp:44
string ToString(Type w)
Converts a WallType::Type value to corresponding name.
Definition: WallType.cpp:49
MeshState GetState() const
The current state of the mesh as a self-contained object.
Definition: Mesh.cpp:494
Combo header for circular iterator.
void Add(const std::string &name)
Adds a named attribute of type T.
const std::list< Wall * > & GetWalls() const
Access the cell's walls.
Definition: Cell.h:88
void UpdateNodeOwningWalls(Wall *wall)
Set ownerships of node <-> cell or update them after cell division.
Definition: Mesh.cpp:829
void UpdateNodeOwningNeighbors(Cell *cell)
Set ownerships of node <-> cell or update them after cell division.
Definition: Mesh.cpp:806
void SetBoundaryPolygonWalls(std::vector< int > wall_ids)
Sets the IDs of the walls that form the boundary polygon of the tissue.
Definition: MeshState.cpp:235
void SetWallID(size_t wall_idx, int value)
Sets the ID of a particular wall.
Definition: MeshState.cpp:274
Definition of WallType.
const std::vector< Cell * > & GetCells() const
The cells of this mesh, EXCLUDING the boundary polygon.
Definition: Mesh.h:108
void SetNodeID(size_t node_idx, int value)
Sets the ID of a particular node.
Definition: MeshState.cpp:70
CircularIterator< typename T::iterator > make_circular(T &c)
Helper produces non-const circular iterator whose range corresponds to the begin and end iterators of...
Namespace for the core simulator.
void ConstructNeighborList(Cell *cell)
Constructs neighbor list by looping over walls and registering adjoining cell for that wall...
Definition: Mesh.cpp:252
An Edge connects two nodes and is ambidextrous.
Definition: Edge.h:31
std::ostream & Print(std::ostream &os) const
Solely for debugging purposes.
Definition: Mesh.cpp:668
Interface for Cell.
std::vector< NeighborNodes > GetEdgeOwners(const Edge &edge) const
Find the intersecting neighbors of the end points of the edge.
Definition: Mesh.cpp:455
Namespace for container related classes.
void SetCellID(size_t cell_idx, int value)
Sets the ID of a particular cell.
Definition: MeshState.cpp:171
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
void SetNumNodes(size_t n)
Sets the number of nodes in the mesh.
Definition: MeshState.cpp:45
void SetNumWalls(size_t n)
Sets the number of walls in the mesh.
Definition: MeshState.cpp:249
AttributeContainer & WallAttributeContainer()
Adds a new named attribute of type T for the nodes.
Definition: MeshState.h:279
AttributeContainer & NodeAttributeContainer()
Adds a new named attribute of type T for the nodes.
Definition: MeshState.h:100
void AddNodeToCell(Cell *c, Node *n, Node *nb1, Node *nb2)
Add node to cell between existing neighbor nodes.
Definition: Mesh.cpp:84
BoundaryType enumeration class.
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
void SetNumCells(size_t n)
Sets the number of cells in the mesh.
Definition: MeshState.cpp:136
Cell * GetBoundaryPolygon() const
Get the boundary polygon of the mesh.
Definition: Mesh.h:105
void RemoveFromNeighborList(Cell *cell)
Removes the cell from the neighbor list (only do this when deleting this cell).
Definition: Mesh.cpp:758
bool IsInBoundaryPolygon(Node *n) const
True iff the node is one of the nodes of the boundary polygon.
Definition: Mesh.cpp:657
void Set(size_t index, const std::string &name, T value)
Sets the value of a named attribute.
Interface for Node.
int GetIndex() const
Return the index.
Definition: Cell.h:76
const std::vector< Node * > & GetNodes() const
The nodes of the mesh.
Definition: Mesh.h:136
std::list< NeighborNodes > & GetNodeOwningNeighbors(Node *n)
Get the neighbors associated with this node.
Definition: Mesh.h:124
Contains the state of the whole Mesh at a given simulation step.
Definition: MeshState.h:41
boost::property_tree::ptree ToPtree() const
Convert the mesh to a ptree.
Definition: Mesh.cpp:769
Interface for Edge.
CircularIterator< T > next(CircularIterator< T > i)
Helper yields the position the iterator would have if moved forward (in circular fashion) by 1 positi...
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...
Wall * FindWall(const Edge &edge) const
Find the wall including the edge.
Definition: Mesh.cpp:373
const std::vector< Wall * > & GetWalls() const
The walls of this mesh.
Definition: Mesh.h:148
AttributeContainer & CellAttributeContainer()
Adds a new named attribute of type T for the nodes.
Definition: MeshState.h:166
void SetNodeX(size_t node_idx, double value)
Sets the x coordinate of a particular node.
Definition: MeshState.cpp:75
CircularIterator< T > prev(CircularIterator< T > i)
Helper yields the position the iterator would have if moved backward (in circular fashion) by 1 posit...
void SetBoundaryPolygonNodes(std::vector< int > node_ids)
Sets the IDs of the nodes that form the boundary polygon of the tissue.
Definition: MeshState.cpp:230
void SetCellWalls(size_t cell_idx, std::vector< int > wall_ids)
Sets the IDs of walls of a particular cell.
Definition: MeshState.cpp:181
double GetArea() const
Return the area of the cell.
Definition: Cell.cpp:178
A cell wall, runs between cell corner points and consists of wall elements.
Definition: Wall.h:48
Node * GetSecond() const
Get the second node of the edge.
Definition: Edge.h:51
void SetCellNodes(size_t cell_idx, std::vector< int > node_ids)
Sets the IDs of the nodes that form the polygon of a particular cell.
Definition: MeshState.cpp:176
Interface for Mesh.