33 #include <boost/property_tree/ptree.hpp>
34 #include <boost/lexical_cast.hpp>
35 #include <boost/optional.hpp>
54 using boost::optional;
55 using boost::lexical_cast;
65 void operator()(
const void*) {}
69 Mesh::Mesh(
unsigned int num_chemicals)
70 : m_boundary_polygon(nullptr),
73 m_num_chemicals(num_chemicals),
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!");
92 if (*(++ins_pos != c->
GetNodes().end() ? ins_pos : c->
GetNodes().begin()) != nb2) {
94 ((ins_pos--) != c->
GetNodes().begin() ?
112 return (n.GetCell()->GetIndex() == c->
GetIndex());
118 const auto cpos = find_if(own.begin(), own.end(), is_nb);
119 if (cpos->GetNb1() == nb2) {
122 }
else if (cpos->GetNb2() == nb2) {
131 const auto cpos = find_if(own.begin(), own.end(), is_nb);
132 if (cpos->GetNb1() == nb1) {
135 }
else if (cpos->GetNb2() == nb1) {
142 Cell* Mesh::BuildBoundaryPolygon(
const vector<unsigned int>& node_ids)
144 auto new_cell = m_cell_storage.emplace_back(-1, GetNumChemicals());
146 m_boundary_polygon = new_cell;
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]]);
158 return m_boundary_polygon;
161 Cell* Mesh::BuildCell()
163 auto new_cell = m_cell_storage.emplace_back(m_cell_next_id++, GetNumChemicals());
166 m_cells.push_back(c);
170 Cell* Mesh::BuildCell(
const std::vector<unsigned int>& node_ids)
172 return BuildCell(m_cell_next_id, node_ids);
175 Cell* Mesh::BuildCell(
unsigned int id,
const vector<unsigned int>& node_ids)
177 assert((
id >= m_cell_next_id) &&
"Cell id not increasing!");
178 auto new_cell = m_cell_storage.emplace_back(
id++, GetNumChemicals());
181 m_cell_next_id = max(m_cell_next_id,
id);
182 m_cells.push_back(c);
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]]);
197 Node* Mesh::BuildNode(
const array<double, 3>& vec,
bool at_boundary)
199 auto new_node = m_node_storage.emplace_back(m_node_next_id++, vec, at_boundary);
202 m_nodes.push_back(n);
206 Node* Mesh::BuildNode(
unsigned int id,
const array<double, 3>& vec,
bool at_boundary)
208 assert((
id >= m_node_next_id) &&
"Node id not increasing!");
209 auto new_node = m_node_storage.emplace_back(
id++, vec, at_boundary);
212 m_node_next_id = max(m_node_next_id,
id);
213 m_nodes.push_back(n);
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!" );
226 auto new_wall = m_wall_storage.emplace_back(m_wall_next_id++, n1, n2, c1, c2, GetNumChemicals());
228 auto wall = new_wall;
229 m_walls.push_back(wall);
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!" );
243 auto new_wall = m_wall_storage.emplace_back(
id++, n1, n2, c1, c2, GetNumChemicals());
245 auto wall = new_wall;
246 m_wall_next_id = max(m_wall_next_id,
id);
247 m_walls.push_back(wall);
254 list<Cell*>& neighbors = m_wall_neighbors[cell];
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());
269 Cell* neighbor_cell =
nullptr;
272 list<NeighborNodes> owners;
274 copy(owners_first.begin(), owners_first.end(), back_inserter(owners));
276 copy(owners_second.begin(), owners_second.end(), back_inserter(owners));
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()) {
295 if (it->GetCell()->GetIndex() != cell->
GetIndex()) {
305 bool isCorrectNeighbor =
false;
309 if (
Edge(*cit, *
next(cit)) == edge) {
310 isCorrectNeighbor =
true;
312 }
while (!isCorrectNeighbor && ++cit != it->GetCell()->GetNodes().begin());
314 if (isCorrectNeighbor) {
315 neighbor_cell = it->GetCell();
320 assert((neighbor_cell !=
nullptr) &&
"There has to be a neighbor");
321 return neighbor_cell;
361 Node* Mesh::FindNextBoundaryNode(
Node* boundary_node)
const
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();
375 if (m_walls.empty()) {
376 assert(m_cells.size() == 1 &&
"The only case without walls in mesh, is single cell.");
381 Cell* cell1 = neighbors.front().GetCell();
382 Cell* cell2 = neighbors.back().GetCell();
385 auto not_contain_cells = [cell1, cell2](
Wall* w){
386 return (w->GetC1() != cell1 && w->GetC2() != cell1)
387 || (w->GetC1() != cell2 && w->GetC2() != cell2);
391 walls.remove_if(not_contain_cells);
392 assert(!walls.empty() &&
"At least one candidate wall tshould associated with the edge.");
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());
399 for (
auto it = cellNodes.begin(); it != find(cellNodes.begin(), cellNodes.end(), w->GetN2()); it++) {
407 assert(
false &&
"No wall has been found for the given edge.");
412 void Mesh::FixCellIDs()
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;
423 m_cell_next_id = m_cells.size();
426 void Mesh::FixNodeIDs()
429 return n1->GetIndex() < n2->GetIndex();
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;
437 m_node_next_id = m_nodes.size();
440 void Mesh::FixWallIDs()
443 return w1->GetIndex() < w2->GetIndex();
446 sort(m_walls.begin(), m_walls.end(),cmp);
448 for (
auto wall : m_walls) {
449 wall->m_wall_index = i++;
452 m_wall_next_id = m_walls.size();
457 list<NeighborNodes> owners;
469 copy(owners_first.begin(), owners_first.end(), back_inserter(owners));
471 copy(owners_second.begin(), owners_second.end(), back_inserter(owners));
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);
486 n = adjacent_find(n, owners.end(), eql);
489 assert(edge_owners.size() == 4 &&
"An edge can only have two neighboring cells per endpoint.");
504 for (
auto const& n : m_nodes) {
505 state.
SetNodeID(node_idx, n->GetIndex());
528 for (
size_t chem_idx = 0; chem_idx < GetNumChemicals(); ++chem_idx) {
532 for (
auto c : m_cells) {
536 vector<int> cell_nodes;
537 for (
auto const& node : c->
GetNodes()) {
538 cell_nodes.push_back(node->GetIndex());
542 vector<int> cell_walls;
543 for (
auto const& wall : c->
GetWalls()) {
544 cell_walls.push_back(wall->GetIndex());
549 cell_idx,
"type", c->GetCellType());
551 cell_idx,
"area", c->
GetArea());
553 cell_idx,
"solute", c->GetSolute());
555 cell_idx,
"target_area", c->GetTargetArea());
557 cell_idx,
"target_length", c->GetTargetLength());
559 cell_idx,
"dead", c->IsDead());
561 cell_idx,
"div_counter", c->GetDivisionCounter());
563 cell_idx,
"stiffness", c->GetStiffness());
565 cell_idx,
"boundary_type",
ToString(c->GetBoundaryType()));
567 cell_idx,
"fixed", c->IsFixed());
568 for (
size_t chem_idx = 0; chem_idx < GetNumChemicals(); ++chem_idx) {
570 cell_idx,
"chem_" + lexical_cast<
string>(chem_idx),
571 c->GetChemical(chem_idx));
577 vector<int> bp_nodes;
578 for (
auto const& node : m_boundary_polygon->
GetNodes()) {
579 bp_nodes.push_back(node->GetIndex());
582 vector<int> bp_walls;
583 for (
auto const& wall : m_boundary_polygon->
GetWalls()) {
584 bp_walls.push_back(wall->GetIndex());
596 for (
size_t chem_idx = 0; chem_idx < GetNumChemicals(); ++chem_idx) {
598 "trans_1_chem_" + lexical_cast<
string>(chem_idx));
600 "trans_2_chem_" + lexical_cast<
string>(chem_idx));
603 for (
auto const& w : m_walls) {
605 state.
SetWallID(wall_idx, w->GetIndex());
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()));
611 wall_idx,
"length", w->GetLength());
613 wall_idx,
"rest_length", w->GetRestLength());
615 wall_idx,
"rest_length_init", w->GetRestLengthInit());
617 wall_idx,
"strength", w->GetStrength());
620 for (
size_t chem_idx = 0; chem_idx < GetNumChemicals(); ++chem_idx) {
622 wall_idx,
"trans_1_chem_" + lexical_cast<
string>(chem_idx),
623 w->GetTransporters1(chem_idx));
625 wall_idx,
"trans_2_chem_" + lexical_cast<
string>(chem_idx),
626 w->GetTransporters2(chem_idx));
630 }
catch (exception& e) {
631 cout <<
"ERROR in Mesh::GetState(): " << e.what() << endl;
639 auto node1 = FindNextBoundaryNode(e->
GetFirst());
640 auto node2 = FindNextBoundaryNode(e->
GetSecond());
651 if (w->GetC1() == m_boundary_polygon || w->GetC2() == m_boundary_polygon) {
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()) {
671 os <<
"MESH_PRINT_" << i << endl;
672 os <<
"BOUNDARY_CELL" << endl;
673 if (m_boundary_polygon) {
674 m_boundary_polygon->Print(os) << endl;
676 os <<
"CELLS" << endl;
677 for (
auto& cell : m_cells) {
678 cell->Print(os) << endl;
680 os <<
"NODES" << endl;
681 for (
auto& node : m_nodes) {
682 node->Print(os) << endl;
684 os <<
"WALLS" << endl;
685 for (
auto& wall : m_walls) {
686 wall->Print(os) << endl;
688 os <<
"NODE_AND_ITS_NEIGHBOR_NODES" << endl;
690 set<string> ordered_output;
692 for (
auto& pair : m_node_owning_neighbors) {
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;
706 os <<
"==============" << endl;
707 ordered_output.insert(os.str());
709 for (
string s : ordered_output) {
713 os <<
"NODE_AND_ITS_WALLS" << endl;
715 set<string> ordered_output;
717 for (
auto& pair : m_node_owning_walls) {
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;
727 os <<
"==============" << endl;
728 ordered_output.insert(os.str());
730 for (
string s : ordered_output) {
734 os <<
"CELL_AND_ITS_NEIGHBOR_CELLS_HAVING_A_COMMON_WALL" << endl;
736 set<string> ordered_output;
738 for (
auto& pair: m_wall_neighbors) {
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;
748 os <<
"==============" << endl;
749 ordered_output.insert(os.str());
751 for (
string s : ordered_output) {
760 m_wall_neighbors.erase(cell);
765 m_node_owning_neighbors.erase(node);
766 m_node_owning_walls.erase(node);
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());
783 ret_pt.put_child(
"cells", cells_pt);
788 nodes_pt.put(
"count", nodes.size());
789 for (
const auto& node : nodes) {
790 nodes_pt.add_child(
"node_array.node", node->ToPtree());
792 ret_pt.put_child(
"nodes", nodes_pt);
797 walls_pt.put(
"count", walls.size());
798 for (
auto const& w : walls) {
799 walls_pt.add_child(
"wall_array.wall", w->ToPtree());
801 ret_pt.put_child(
"walls", walls_pt);
809 if (!nodes.empty()) {
814 if (owners.size() > 0) {
817 return (n.GetCell()->GetIndex() == cell->
GetIndex());
819 auto nb_it = find_if(owners.begin(), owners.end(), is_nb);
820 if (nb_it != owners.end()) {
825 }
while (++it != nodes.begin());
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");
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);
846 while (++cit != stop) {
847 m_node_owning_walls[*cit] = { wall };
void SetNodeY(size_t node_idx, double value)
Sets the y coordinate of a particular node.
Cell * FindEdgeNeighbor(Cell *cell, Edge edge) const
Find the neighbor to this cell with respect to the given edge.
bool IsAtBoundary(const Edge *e) const
True iff the edge is on the mesh boundary.
A cell contains walls and nodes.
void RemoveNodeFromOwnerLists(Node *node)
Removes the node from the 'node owning neighbors' and 'node owning walls' lists.
Cell * GetCell() const
Return the cell of this Neighbor pair.
Namespace for miscellaneous utilities.
string ToString(Type w)
Converts a WallType::Type value to corresponding name.
MeshState GetState() const
The current state of the mesh as a self-contained object.
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.
void UpdateNodeOwningWalls(Wall *wall)
Set ownerships of node <-> cell or update them after cell division.
void UpdateNodeOwningNeighbors(Cell *cell)
Set ownerships of node <-> cell or update them after cell division.
void SetBoundaryPolygonWalls(std::vector< int > wall_ids)
Sets the IDs of the walls that form the boundary polygon of the tissue.
void SetWallID(size_t wall_idx, int value)
Sets the ID of a particular wall.
const std::vector< Cell * > & GetCells() const
The cells of this mesh, EXCLUDING the boundary polygon.
void SetNodeID(size_t node_idx, int value)
Sets the ID of a particular node.
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...
An Edge connects two nodes and is ambidextrous.
std::ostream & Print(std::ostream &os) const
Solely for debugging purposes.
std::vector< NeighborNodes > GetEdgeOwners(const Edge &edge) const
Find the intersecting neighbors of the end points of the edge.
Namespace for container related classes.
void SetCellID(size_t cell_idx, int value)
Sets the ID of a particular cell.
Macro defs for debug and logging.
Structure of neighboring nodes: two neighboring nodes from standpoint of a given cell with an orderin...
void SetNumNodes(size_t n)
Sets the number of nodes in the mesh.
void SetNumWalls(size_t n)
Sets the number of walls in the mesh.
AttributeContainer & WallAttributeContainer()
Adds a new named attribute of type T for the nodes.
AttributeContainer & NodeAttributeContainer()
Adds a new named attribute of type T for the nodes.
void AddNodeToCell(Cell *c, Node *n, Node *nb1, Node *nb2)
Add node to cell between existing neighbor nodes.
BoundaryType enumeration class.
Node * GetFirst() const
Get the first node of the edge.
const std::vector< Node * > & GetNodes() const
Access the nodes of cell's polygon.
void SetNumCells(size_t n)
Sets the number of cells in the mesh.
Cell * GetBoundaryPolygon() const
Get the boundary polygon of the mesh.
void RemoveFromNeighborList(Cell *cell)
Removes the cell from the neighbor list (only do this when deleting this cell).
bool IsInBoundaryPolygon(Node *n) const
True iff the node is one of the nodes of the boundary polygon.
void Set(size_t index, const std::string &name, T value)
Sets the value of a named attribute.
int GetIndex() const
Return the index.
const std::vector< Node * > & GetNodes() const
The nodes of the mesh.
std::list< NeighborNodes > & GetNodeOwningNeighbors(Node *n)
Get the neighbors associated with this node.
Contains the state of the whole Mesh at a given simulation step.
boost::property_tree::ptree ToPtree() const
Convert the mesh to a ptree.
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.
const std::vector< Wall * > & GetWalls() const
The walls of this mesh.
AttributeContainer & CellAttributeContainer()
Adds a new named attribute of type T for the nodes.
void SetNodeX(size_t node_idx, double value)
Sets the x coordinate of a particular node.
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.
void SetCellWalls(size_t cell_idx, std::vector< int > wall_ids)
Sets the IDs of walls of a particular cell.
double GetArea() const
Return the area of the cell.
A cell wall, runs between cell corner points and consists of wall elements.
Node * GetSecond() const
Get the second node of the edge.
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.