diff --git a/src/mesh.cpp b/src/mesh.cpp
new file mode 100644
--- /dev/null
+++ b/src/mesh.cpp
@@ -0,0 +1,2266 @@
+/*
+ *
+ * This file is part of the Virtual Leaf.
+ *
+ * The Virtual Leaf is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Virtual Leaf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the Virtual Leaf. If not, see .
+ *
+ * Copyright 2010 Roeland Merks.
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+//#include
+#include
+#include
+#include
+#include
+#include
+#include "mesh.h"
+#include "tiny.h"
+#include "parameter.h"
+#include "random.h"
+#include "pi.h"
+#include "parse.h"
+#include "matrix.h"
+#include "sqr.h"
+#include "nodeset.h"
+#include "nodeitem.h"
+#include "simplugin.h"
+
+#include
+#include
+#include
+#include
+
+static const std::string _module_id("$Id$");
+
+extern Parameter par;
+
+void Mesh::AddNodeToCellAtIndex(Cell *c, Node *n, Node *nb1, Node *nb2, list::iterator ins_pos) {
+ c->nodes.insert(ins_pos, n);
+ n->owners.push_back( Neighbor(c, nb1, nb2 ) );
+}
+
+
+void Mesh::AddNodeToCell(Cell *c, Node *n, Node *nb1, Node *nb2) {
+
+ c->nodes.push_back( n );
+ n->owners.push_back( Neighbor(c, nb1, nb2 ) );
+
+}
+
+void Mesh::PerturbChem(int chemnum, double range) {
+
+ for (vector::iterator i=cells.begin();
+ i!=cells.end();
+ i++) {
+ (*i)->chem[chemnum] += range*(RANDOM()-0.5);
+ if ((*i)->chem[chemnum]<0.) (*i)->chem[chemnum]=0.;
+ }
+
+}
+
+void Mesh::CellFiles(const Vector ll, const Vector ur) {
+
+ Cell *cell = RectangularCell(ll,ur,0.001);
+
+ for (int c=0;cSetChemical(c,par.initval[c]);
+ }
+
+ cell->SetTargetArea(cell->CalcArea());
+
+ Vector axis(1,0,0);
+
+ // divide rectangle a number of times
+ for (int i=0;i<6;i++) {
+ IncreaseCellCapacityIfNecessary();
+
+ vector current_cells = cells;
+ for (vector::iterator j=current_cells.begin();
+ j!=current_cells.end();j++) {
+ (*j)->DivideOverAxis(axis);
+ }
+ axis=axis.Perp2D();
+
+ }
+
+ IncreaseCellCapacityIfNecessary();
+
+ axis=axis.Perp2D();
+
+ vector current_cells = cells;
+ for (vector::iterator j=current_cells.begin();
+ j!=current_cells.end();j++) {
+ (*j)->DivideOverAxis(axis);
+ }
+
+
+ double sum_l=0; int n_l=0;
+ for (list::const_iterator i=cell->nodes.begin();
+ i!=cell->nodes.end();
+ i++) {
+ list::const_iterator nb=i; nb++;
+ if (nb==cell->nodes.end())
+ nb=cell->nodes.begin();
+
+ double l = (**nb-**i).Norm();
+
+ sum_l += l;
+ n_l++;
+
+ }
+
+
+ Node::target_length = sum_l/(double)n_l;
+ // a bit more tension
+ Node::target_length/=4.;
+
+ SetBaseArea();
+
+}
+
+Cell *Mesh::RectangularCell(const Vector ll, const Vector ur, double rotation) {
+
+ Cell *cell=AddCell(new Cell());
+ cell->m=this;
+
+ Matrix rotmat;
+ rotmat.Rot2D(rotation); // rotation over 0,0
+
+ Node *n1=AddNode(new Node(rotmat * ll));
+ Node *n2=AddNode(new Node(rotmat * Vector(ll.x, ur.y,0)));
+ Node *n3=AddNode(new Node(rotmat * ur));
+ Node *n4=AddNode(new Node(rotmat * Vector(ur.x, ll.y,0)));
+
+ n1->boundary=true;
+ n2->boundary=true;
+ n3->boundary=true;
+ n4->boundary=true;
+
+ //n1.fixed=n2.fixed=n3.fixed=n4.fixed=true;
+
+ AddNodeToCell(cell, n4,
+ n1,
+ n3);
+
+ AddNodeToCell(cell, n3,
+ n4,
+ n2);
+
+ AddNodeToCell(cell, n2,
+ n3,
+ n1);
+
+ AddNodeToCell(cell, n1,
+ n2,
+ n4);
+
+
+ AddNodeToCell(boundary_polygon, n4,
+ n1,
+ n3);
+ AddNodeToCell(boundary_polygon, n3,
+ n4,
+ n2);
+ AddNodeToCell(boundary_polygon, n2,
+ n3,
+ n1);
+ AddNodeToCell(boundary_polygon, n1,
+ n2,
+ n4);
+
+ cell->setCellVec(Vector(0,1,0));
+
+ boundary_polygon->m = this;
+ boundary_polygon->area = 0;
+
+ cell->area = cell->CalcArea();
+ // target length is the length of the elements
+
+ Node::target_length = ur.y-ll.y;
+ // a bit more tension
+ Node::target_length/=2;
+
+ cell->SetIntegrals();
+ cell->ConstructNeighborList();
+
+ return cell;
+}
+
+Cell &Mesh::EllipticCell(double xc, double yc, double ra, double rb, int nnodes, double rotation) {
+
+ int first_node=Node::nnodes;
+ // nodes.reserve(nodes.size()+nnodes);
+
+
+ //cells.push_back(Cell(xc,yc));
+ Cell *c=AddCell(new Cell(xc,yc));
+ c->m=this;
+
+ for (int i=0;iboundary = true;
+
+ }
+
+ for (int i=0;im = this;
+ boundary_polygon->area = 0;
+
+ c->area = c->CalcArea();
+ // target length is the length of the elements
+
+ Node::target_length = (2 * ((ra +rb)/2.) * sin (Pi/nnodes));
+ // a bit more tension
+ Node::target_length/=2;
+
+ //boundary_polygon = c;
+ /* list::iterator nb;
+ for (list::iterator i=c->nodes.begin();
+ i!=c->nodes.end();
+ i++) {
+
+ nb = i; nb++;
+ if (nb==c->nodes.end()) {
+ nb=c->nodes.begin();
+ }
+ int next = *nb;
+
+ nb = i;
+ if (nb==c->nodes.begin()) {
+ nb=c->nodes.end();
+ }
+ nb--;
+ int previous = *nb;
+
+
+ getNode(*i).cells.push_back( Neighbor(boundary_polygon->index, next, previous) );
+ }*/
+
+ c->SetIntegrals();
+ //c->ConstructNeighborList();
+
+ //c->ConstructWalls();
+
+ // initial cell has one wall with the outside world
+ //c->walls.push_back( new Wall ( nodes.front(), nodes.front(), c, boundary_polygon ));
+
+ c->at_boundary=true;
+
+ return *c;
+
+
+}
+
+Cell &Mesh::LeafPrimordium(int nnodes, double pet_length) {
+
+ // first leaf cell
+
+ int first_node=Node::nnodes;
+
+ Cell *circle=AddCell(new Cell(0,0));
+ circle->m=this;
+ const double ra=10, rb=10;
+ const double xc=0,yc=0;
+ const double rotation=0;
+ for (int i=0;i 1.25*Pi && angle < 1.75*Pi ) {
+ n.sam = true;
+ }*/
+
+ AddNodeToCell(circle,
+ n,
+ nodes[first_node+ (nnodes+i-1)%nnodes],
+ nodes[first_node+ (i + 1)%nnodes]);
+
+ }
+
+ boundary_polygon->m = this;
+ boundary_polygon->area = 0;
+
+ circle->area = circle->CalcArea();
+ // target length is the length of the elements
+
+ Node::target_length = (2 * ((ra +rb)/2.) * sin (Pi/nnodes));
+ // a bit more tension
+ Node::target_length/=2;
+
+ circle->SetIntegrals();
+
+ //return c;
+
+ circle->SetTargetArea(2*circle->Area());
+
+ // Petiole: starts at both sides of the circular cell
+ // get position of the (n/4)'th and (3*(n/4))'th node.
+
+ list::reverse_iterator it_n1=circle->nodes.rbegin();
+ for (int i=0;i::reverse_iterator it_n2=--circle->nodes.rend();
+ /* for (int i=0;iboundary=true;
+ n4->boundary=true;
+
+ AddNodeToCell(petiole, *it_n1,
+ n4,
+ nodes[(*it_n2)->Index()
+ + (( (*it_n1)->Index() - (*it_n2)->Index() )-1+nnodes)%nnodes]);
+
+
+
+ list::reverse_iterator i=it_n1; i++;
+ for (;
+ i!=it_n2;
+ //(++i) == circle->nodes.rend() ? i : i=circle->nodes.rbegin() ) {
+ ++i) {
+ AddNodeToCell(petiole,
+ *i,
+ nodes[(*it_n2)->Index() + (((*i)->Index()-(*it_n2)->Index()) + 1)%nnodes],
+ nodes[(*it_n2)->Index() + (((*i)->Index()-(*it_n2)->Index())-1+nnodes)%nnodes]);
+
+ }
+
+
+ AddNodeToCell(petiole, *it_n2,
+ *it_n2 + 1,
+ n3);
+
+
+ (*it_n2)->boundary=true;
+
+ //petiole.nodes.push_back(n3.Index());
+ //petiole.nodes.push_back(n4.Index());
+ AddNodeToCell(petiole,
+ n3,
+ n2,
+ n4);
+ AddNodeToCell(petiole,
+ n4,
+ n3,
+ n1);
+
+
+
+ cerr << circle << endl;
+ cerr << petiole << endl;
+
+ AddNodeToCell(boundary_polygon, *it_n1,
+ n4,
+ *it_n2 + ((*it_n1-*it_n2)+1)%nnodes); // is this gonna work?
+
+ (*it_n1)->boundary=true;
+
+ for (int i=0;iowners.size()==1) {
+ AddNodeToCell(boundary_polygon,
+ nodes[first_node +i],
+ nodes[first_node+ (nnodes+i-1)%nnodes],
+ nodes[first_node+ (i + 1)%nnodes]);
+
+ nodes[first_node+i]->boundary=true;
+ }
+ }
+
+ AddNodeToCell(boundary_polygon, *it_n2,
+ nodes[(nnodes+(*it_n2)->Index() - 1)%nnodes],
+ n3);
+
+ AddNodeToCell(boundary_polygon,
+ n3,
+ n2,
+ n4);
+ AddNodeToCell(boundary_polygon,
+ n4,
+ n3,
+ n1);
+
+ // make petiole solid
+ for (list::iterator i=petiole->nodes.begin();
+ i!=petiole->nodes.end();
+ i++) {
+ (*i)->Fix();
+ }
+ petiole->Fix();
+
+ petiole->area=petiole->CalcArea();
+ petiole->target_area=petiole->area;
+ petiole->ConstructNeighborList();
+ circle->ConstructNeighborList();
+ boundary_polygon->ConstructConnections();
+ boundary_polygon->ConstructNeighborList();
+
+ circle->setCellVec(Vector(0,1,0));
+
+ return *circle;
+}
+
+/*Cell &Mesh::Box() {
+
+
+
+}*/
+
+
+// return bounding box of mesh
+void Mesh::BoundingBox(Vector &LowerLeft, Vector &UpperRight) {
+
+ LowerLeft = **nodes.begin();
+ UpperRight = **nodes.begin();
+ for (vector::iterator c=nodes.begin();
+ c!=nodes.end();
+ c++) {
+ if ((*c)->x < LowerLeft.x)
+ LowerLeft.x = (*c)->x;
+ if ((*c)->y < LowerLeft.y)
+ LowerLeft.y = (*c)->y;
+ if ((*c)->z < LowerLeft.z)
+ LowerLeft.z = (*c)->z;
+ if ((*c)->x > UpperRight.x)
+ UpperRight.x = (*c)->x;
+ if ((*c)->y > UpperRight.y)
+ UpperRight.y = (*c)->y;
+ if ((*c)->z > UpperRight.z)
+ UpperRight.z = (*c)->z;
+ }
+
+}
+
+
+double Mesh::Area(void) {
+
+ double area=0;
+ vector::iterator i=cells.begin();
+ while (i != cells.end()) {
+ area += (*(i++))->Area();
+ }
+ return area;
+}
+
+void Mesh::SetBaseArea(void) {
+
+ // Set base area to mean area.
+ // This method is typically called during initiation, after
+ // defining the first cell
+ Cell::BaseArea() = Area()/cells.size();
+}
+
+// for optimization, we moved Displace to Mesh
+
+class DeltaIntgrl {
+
+public:
+ double area;
+ double ix, iy;
+ double ixx,ixy,iyy;
+ DeltaIntgrl(double sarea,double six,double siy,double sixx,double sixy,double siyy) {
+ area=sarea;
+ ix=six;
+ iy=siy;
+ ixx=sixx;
+ ixy=sixy;
+ iyy=siyy;
+ }
+};
+
+void Mesh::Clear(void) {
+
+ // clear nodes
+ for (vector::iterator i=nodes.begin();
+ i!=nodes.end();
+ i++) {
+ delete *i;
+ }
+
+ nodes.clear();
+ Node::nnodes=0;
+
+ node_insertion_queue.clear();
+ // Clear NodeSets
+ for (vector::iterator i=node_sets.begin();
+ i!=node_sets.end();
+ i++) {
+ delete *i;
+ }
+
+ node_sets.clear();
+ time = 0;
+
+ // clear cells
+
+ for (vector::iterator i=cells.begin();
+ i!=cells.end();
+ i++) {
+ delete *i;
+ }
+
+ cells.clear();
+ Cell::NCells() = 0;
+
+ delete boundary_polygon;
+
+ // Clear walls
+ for (list::iterator i=walls.begin();
+ i!=walls.end();
+ i++) {
+ delete *i;
+ }
+
+ walls.clear();
+ WallBase::nwalls = 0;
+ //tmp_walls->clear();
+
+ shuffled_cells.clear();
+ shuffled_nodes.clear();
+ //Cell::ncells=0;
+ /* Cell::ClearNCells();
+ Node::nnodes=0;
+
+ cells.clear();
+ nodes.clear();
+ shuffled_cells.clear();
+ shuffled_nodes.clear();
+ node_insertion_queue.empty();
+
+ cerr << "Meshed cleared: cells: " << cells.size() << ", nodes: " << nodes.size() << endl;
+ */
+
+ cerr << "cells.size() = " << cells.size() << endl;
+ cerr << "walls.size() = " << walls.size() << endl;
+ cerr << "nodes.size() = " << nodes.size() << endl;
+}
+
+double Mesh::DisplaceNodes(void) {
+
+ MyUrand r(shuffled_nodes.size());
+ random_shuffle(shuffled_nodes.begin(),shuffled_nodes.end(),r);
+
+ double sum_dh=0;
+
+ list delta_intgrl_list;
+
+ for_each( node_sets.begin(), node_sets.end(), mem_fun( &NodeSet::ResetDone ) );
+
+ for (vector::const_iterator i=shuffled_nodes.begin();
+ i!=shuffled_nodes.end();
+ i++) {
+
+ //int n=shuffled_nodes[*i];
+ Node &node(**i);
+
+ // Do not allow displacement if fixed
+ //if (node.fixed) continue;
+
+ if (node.DeadP()) continue;
+
+ // Attempt to move this cell in a random direction
+ double rx=par.mc_stepsize*(RANDOM()-0.5); // was 100.
+ double ry=par.mc_stepsize*(RANDOM()-0.5);
+
+ // Uniform with a circle of radius par.mc_stepsize
+ /* double r = RANDOM() * par.mc_stepsize;
+ double th = RANDOM()*2*Pi;
+
+ double rx = r * cos(th);
+ double ry = r * sin(th);
+ */
+ Vector new_p(node.x+rx,node.y+ry,0);
+ Vector old_p(node.x,node.y,0);
+
+ /* if (node.boundary && boundary_polygon->MoveSelfIntersectsP(n, new_p )) {
+ // reject if move of boundary results in self intersection
+ continue;
+ }*/
+
+
+ if (node.node_set) {
+ // move each node set only once
+ if (!node.node_set->DoneP())
+ node.node_set->AttemptMove(rx,ry);
+
+ } else {
+
+ // for all cells to which this node belongs:
+ // calculate energy difference
+
+ double area_dh=0.;
+ double length_dh=0.;
+ double bending_dh=0.;
+ double cell_length_dh=0.;
+ double alignment_dh=0.;
+
+ double old_l1=0.,old_l2=0.,new_l1=0.,new_l2=0.;
+
+ double sum_stiff=0.;
+ double dh=0.;
+
+ for (list::const_iterator cit=node.owners.begin();
+ cit!=node.owners.end();
+ cit++) {
+
+ //Cell &c=m->getCell(cit->cell);
+ //Cell &c=cit->cell->BoundaryPolP()?*boundary_polygon:*(cit->cell);
+ Cell &c=*((Cell *)(cit->cell));
+ //Cell &c=cells[cit->cell];
+ if (c.MoveSelfIntersectsP(&node, new_p )) {
+ // reject if move results in self intersection
+ //
+ // I know: using goto's is bad practice... except when jumping out
+ // of deeply nested loops :-)
+ //cerr << "Rejecting due to self-intersection\n";
+ goto next_node;
+ }
+
+ // summing stiffnesses of cells. Move has to overcome this minimum required energy.
+ sum_stiff += c.stiffness;
+ // area - (area after displacement): see notes for derivation
+ //Vector i_min_1 = m->getNode(cit->nb1);
+
+ Vector i_min_1 = *(cit->nb1);
+ //Vector i_plus_1 = m->getNode(cit->nb2);
+ Vector i_plus_1 = *(cit->nb2);
+
+
+ // We must double the weights for the perimeter (otherwise they start bulging...)
+ double w1, w2;
+ if (node.boundary && cit->nb1->boundary)
+#ifdef FLEMING
+ w1 = par.rel_perimeter_stiffness;
+#else
+ w1=2;
+#endif
+ else
+ w1 = 1;
+
+ if (node.boundary && cit->nb2->boundary)
+#ifdef FLEMING
+ w2 = par.rel_perimeter_stiffness;
+#else
+ w2 = 2;
+#endif
+ else
+ w2 = 1;
+
+ //if (cit->cell>=0) {
+ if (!cit->cell->BoundaryPolP()) {
+ double delta_A = 0.5 * ( ( new_p.x - old_p.x ) * (i_min_1.y - i_plus_1.y) +
+ ( new_p.y - old_p.y ) * ( i_plus_1.x - i_min_1.x ) );
+
+ area_dh += delta_A * (2 * c.target_area - 2 * c.area + delta_A);
+
+
+ // cell length constraint
+ // expensive and not always needed
+ // so we check the value of lambda_celllength
+
+ if (/* par.lambda_celllength */ cit->cell->lambda_celllength) {
+
+ double delta_ix =
+ (i_min_1.x + new_p.x)
+ * (new_p.x * i_min_1.y- i_min_1.x * new_p.y) +
+ (new_p.x + i_plus_1.x)
+ * (i_plus_1.x * new_p.y- new_p.x * i_plus_1.y) -
+
+ (i_min_1.x + old_p.x)
+ * (old_p.x * i_min_1.y- i_min_1.x * old_p.y) -
+ (old_p.x + i_plus_1.x)
+ * (i_plus_1.x * old_p.y - old_p.x * i_plus_1.y);
+
+
+ double delta_iy =
+ (i_min_1.y + new_p.y)
+ * (new_p.x * i_min_1.y- i_min_1.x * new_p.y) +
+ (new_p.y + i_plus_1.y)
+ * (i_plus_1.x * new_p.y- new_p.x * i_plus_1.y) -
+
+ (i_min_1.y + old_p.y)
+ * (old_p.x * i_min_1.y- i_min_1.x * old_p.y) -
+ (old_p.y + i_plus_1.y)
+ * (i_plus_1.x * old_p.y - old_p.x * i_plus_1.y);
+
+
+ double delta_ixx =
+ (new_p.x*new_p.x+
+ i_min_1.x*new_p.x+
+ i_min_1.x*i_min_1.x ) *
+ (new_p.x*i_min_1.y - i_min_1.x*new_p.y) +
+
+ (i_plus_1.x*i_plus_1.x+
+ new_p.x*i_plus_1.x+
+ new_p.x*new_p.x ) *
+ (i_plus_1.x*new_p.y - new_p.x*i_plus_1.y) -
+
+ (old_p.x*old_p.x+
+ i_min_1.x*old_p.x+
+ i_min_1.x*i_min_1.x ) *
+ (old_p.x*i_min_1.y - i_min_1.x*old_p.y) -
+
+ (i_plus_1.x*i_plus_1.x+
+ old_p.x*i_plus_1.x+
+ old_p.x*old_p.x ) *
+ (i_plus_1.x*old_p.y - old_p.x*i_plus_1.y);
+
+
+ double delta_ixy =
+ (i_min_1.x*new_p.y-
+ new_p.x*i_min_1.y)*
+ (new_p.x*(2*new_p.y+i_min_1.y)+
+ i_min_1.x*(new_p.y+2*i_min_1.y)) +
+
+ (new_p.x*i_plus_1.y-
+ i_plus_1.x*new_p.y)*
+ (i_plus_1.x*(2*i_plus_1.y+new_p.y)+
+ new_p.x*(i_plus_1.y+2*new_p.y)) -
+
+ (i_min_1.x*old_p.y-
+ old_p.x*i_min_1.y)*
+ (old_p.x*(2*old_p.y+i_min_1.y)+
+ i_min_1.x*(old_p.y+2*i_min_1.y)) -
+
+ (old_p.x*i_plus_1.y-
+ i_plus_1.x*old_p.y)*
+ (i_plus_1.x*(2*i_plus_1.y+old_p.y)+
+ old_p.x*(i_plus_1.y+2*old_p.y));
+
+
+ double delta_iyy =
+ (new_p.x*i_min_1.y-
+ i_min_1.x*new_p.y)*
+ (new_p.y*new_p.y+
+ i_min_1.y*new_p.y+
+ i_min_1.y*i_min_1.y ) +
+
+ (i_plus_1.x*new_p.y-
+ new_p.x*i_plus_1.y)*
+ (i_plus_1.y*i_plus_1.y+
+ new_p.y*i_plus_1.y+
+ new_p.y*new_p.y ) -
+
+ (old_p.x*i_min_1.y-
+ i_min_1.x*old_p.y)*
+ (old_p.y*old_p.y+
+ i_min_1.y*old_p.y+
+ i_min_1.y*i_min_1.y ) -
+
+ (i_plus_1.x*old_p.y-
+ old_p.x*i_plus_1.y)*
+ (i_plus_1.y*i_plus_1.y+
+ old_p.y*i_plus_1.y+
+ old_p.y*old_p.y );
+
+ delta_intgrl_list.push_back(DeltaIntgrl(delta_A,delta_ix,delta_iy,delta_ixx,delta_ixy,delta_iyy));
+
+ Vector old_axis;
+ double old_celllength = c.Length(&old_axis);
+ old_axis=old_axis.Normalised().Perp2D();
+
+ // calculate length after proposed update
+ double intrx=(c.intgrl_x-delta_ix)/6.;
+ double intry=(c.intgrl_y-delta_iy)/6.;
+ double ixx=((c.intgrl_xx-delta_ixx)/12.)-(intrx*intrx)/(c.area-delta_A);
+ double ixy=((c.intgrl_xy-delta_ixy)/24.)+(intrx*intry)/(c.area-delta_A);
+ double iyy=((c.intgrl_yy-delta_iyy)/12.)-(intry*intry)/(c.area-delta_A);
+
+ double rhs1=(ixx+iyy)/2., rhs2=sqrt( (ixx-iyy)*(ixx-iyy)+4*ixy*ixy )/2.;
+
+ double lambda_b=rhs1+rhs2;
+
+
+ double new_celllength=4*sqrt(lambda_b/(c.area-delta_A));
+ //cerr << "new_celllength = " << new_celllength << endl;
+ //cerr << "target_length = " << c.target_length << endl;
+
+ cell_length_dh += c.lambda_celllength * ( DSQR(c.target_length - new_celllength) - DSQR(c.target_length-old_celllength) );
+
+ Vector norm_long_axis(lambda_b - ixx, ixy, 0);
+ norm_long_axis.Normalise();
+
+ double alignment_before = InnerProduct(old_axis, c.cellvec);
+ double alignment_after = InnerProduct(norm_long_axis, c.cellvec);
+
+ /* cerr << "Delta alignment = " << alignment_before - alignment_after << endl;
+ cerr << "Old alignment is " << alignment_before << ", new alignment is " << alignment_after << endl;
+ cerr << "Old axis is " << old_axis << ", new axis is " << norm_long_axis << endl;
+ */
+ alignment_dh += alignment_before - alignment_after;
+
+ /* cerr << "alignment_dh = " << alignment_dh << endl;
+ cerr << "cellvec = " << c.cellvec << endl;*/
+
+ } else {
+ // if we have no length constraint, still need to update area
+ delta_intgrl_list.push_back(DeltaIntgrl(delta_A,0,0,0,0,0));
+
+ }
+
+ old_l1=(old_p-i_min_1).Norm();
+ old_l2=(old_p-i_plus_1).Norm();
+ new_l1=(new_p-i_min_1).Norm();
+ new_l2=(new_p-i_plus_1).Norm();
+
+
+
+
+ static int count=0;
+ // Insertion of nodes (cell wall yielding)
+ if (!node.fixed) {
+ if (old_l1 > 4*Node::target_length && !cit->nb1->fixed) {
+ node_insertion_queue.push( Edge(cit->nb1, &node) );
+ }
+ if (old_l2 > 4*Node::target_length && !cit->nb2->fixed) {
+ node_insertion_queue.push( Edge(&node, cit->nb2 ) );
+ }
+ count++;
+ /*length_dh += 2*Node::target_length * (old_l1 + old_l2 - new_l1 - new_l2)
+ + DSQR(new_l1) - DSQR(old_l1) + DSQR(new_l2) - DSQR(old_l2);*/
+ }
+ /* length_dh += 2*Node::target_length * ( w1*(old_l1 - new_l1) +
+ w2*(old_l2 - new_l2) ) +
+ w1*(DSQR(new_l1)
+ - DSQR(old_l1))
+ + w2*(DSQR(new_l2)
+ - DSQR(old_l2)); */
+
+
+ /* if (c.cellvec.ManhattanNorm()!=0) {
+
+ // wall element length constraint
+ double old_aniso1, old_aniso2;
+ double new_aniso1, new_aniso2;
+
+ // anisotropic expansion?
+ old_aniso1 = 1 + par.lambda_aniso*(1 - fabs(InnerProduct((old_p-i_min_1), c.cellvec))/old_l1);
+ old_aniso2 = 1 + par.lambda_aniso*(1 - fabs(InnerProduct((old_p-i_plus_1), c.cellvec))/old_l2);
+ new_aniso1 = 1 + par.lambda_aniso*(1 - fabs(InnerProduct((new_p-i_min_1), c.cellvec))/new_l1);
+ new_aniso2 = 1 + par.lambda_aniso*(1 - fabs(InnerProduct((new_p-i_plus_1), c.cellvec))/new_l2);
+
+
+ length_dh += w1 * ( new_aniso1 * DSQR(new_l1 - Node::target_length) -
+ old_aniso1 * DSQR(old_l1 - Node::target_length) )
+ + w2 * ( new_aniso2 * DSQR(new_l2 - Node::target_length) -
+ old_aniso2 * DSQR(old_l2 - Node::target_length) );
+
+ } else {
+ */
+ length_dh += 2*Node::target_length * ( w1*(old_l1 - new_l1) +
+ w2*(old_l2 - new_l2) ) +
+ w1*(DSQR(new_l1)
+ - DSQR(old_l1))
+ + w2*(DSQR(new_l2)
+ - DSQR(old_l2));
+
+
+ //}
+
+
+
+ }
+
+ // bending energy also holds for outer boundary
+ // first implementation. Can probably be done more efficiently
+ // calculate circumcenter radius (gives local curvature)
+ // the ideal bending state is flat... (K=0)
+ // if (cit->cell==-1 && node.cells.size()>2 /* boundary_pol, cell and a second cell */) {
+ {
+ // strong bending energy to resist "cleaving" by division planes
+ double r1, r2, xc, yc;
+ CircumCircle(i_min_1.x, i_min_1.y, old_p.x, old_p.y, i_plus_1.x, i_plus_1.y,
+ &xc,&yc,&r1);
+ CircumCircle(i_min_1.x, i_min_1.y, new_p.x, new_p.y, i_plus_1.x, i_plus_1.y,
+ &xc,&yc, &r2);
+
+ if (r1<0 || r2<0) {
+ MyWarning::warning("r1 = %f, r2 = %f",r1,r2);
+ }
+ bending_dh += DSQR(1/r2 - 1/r1);
+ //bending_dh += ( DSQR(1/r2) - DSQR(1/r1) );
+
+ //cerr << "bending_dh = " << par.bend_lambda*bending_dh << endl;
+
+ }
+ /*cerr << "Bending = " << ( DSQR(1/r2) - DSQR(1/r1)) << endl;
+ cerr << node.index << ": " << bending_dh << " (" << r1 << ", " << r2 << ") " << cit->nb1 << ", " << cit->nb2 << ")" << endl;
+ }*/
+ /*else
+ bending_dh += ( DSQR(1/r2) - DSQR(1/r1) );*/
+
+
+ /*if (cit->cell==-1) {
+ cerr << node.index << ": " << bending_dh << " (" << r1 << ", " << r2 << ") " << cit->nb1 << ", " << cit->nb2 << ")" << endl;
+ }*/
+
+ //bending_dh += r1 - r2;
+
+ }
+
+ //const double bend_lambda = 100000;
+ //const double bend_lambda = 0;
+
+ /* double dh = //(area_dev_sum_after - area_dev_sum_before) +
+ area_dh + par.lambda_celllength * cell_length_dh +
+ par.lambda_length * length_dh + par.bend_lambda * bending_dh + par.alignment_lambda * alignment_dh;*/
+
+ dh = //(area_dev_sum_after - area_dev_sum_before) +
+ area_dh + cell_length_dh +
+ par.lambda_length * length_dh + par.bend_lambda * bending_dh + par.alignment_lambda * alignment_dh;
+
+ //cerr << "cell_length_dh = " << par.lambda_celllength * cell_length_dh << endl;
+ //(length_constraint_after - length_constraint_before);
+
+ if (node.fixed) {
+
+ // search the fixed cell to which this node belongs
+ // and displace these cells as a whole
+ // WARNING: undefined things will happen for connected fixed cells...
+ for (list::iterator c=node.owners.begin();
+ c!=node.owners.end();
+ c++) {
+ if (!c->cell->BoundaryPolP() && c->cell->FixedP()) {
+ sum_dh+=c->cell->Displace(rx,ry,0);
+ }
+ }
+ } else {
+
+
+ if (dh<-sum_stiff || RANDOM()::const_iterator di_it = delta_intgrl_list.begin();
+ for (list::iterator cit=node.owners.begin();
+ cit!=node.owners.end();
+ ( cit++) ) {
+ //m->getCell(cit->cell).area -= *da_it;
+ //if (cit->cell>=0) {
+ if (!cit->cell->BoundaryPolP()) {
+ cit->cell->area -= di_it->area;
+ if (par.lambda_celllength) {
+ cit->cell->intgrl_x -= di_it->ix;
+ cit->cell->intgrl_y -= di_it->iy;
+ cit->cell->intgrl_xx -= di_it->ixx;
+ cit->cell->intgrl_xy -= di_it->ixy;
+ cit->cell->intgrl_yy -= di_it->iyy;
+ }
+ di_it++;
+ }
+ }
+
+ double old_nodex, old_nodey;
+
+ old_nodex=node.x;
+ old_nodey=node.y;
+
+ node.x = new_p.x;
+ node.y = new_p.y;
+
+ for (list::iterator cit=node.owners.begin();
+ cit!=node.owners.end();
+ ( cit++) ) {
+
+ /* if (cit->cell >= 0 && cells[cit->cell].SelfIntersect()) {
+ node.x = old_nodex;
+ node.y = old_nodey;
+ goto next_node;
+ }*/
+ }
+ sum_dh += dh;
+ }
+ }
+ }
+ next_node:
+ delta_intgrl_list.clear();//dA_list.clear();
+
+ }
+
+ return sum_dh;
+
+}
+
+
+void Mesh::InsertNode(Edge &e) {
+
+
+ // Construct a new node in the middle of the edge
+ Node *new_node = AddNode( new Node ( ( *e.first + *e.second )/2 ) );
+
+ // if new node is inserted into the boundary
+ // it will be part of the boundary, fixed, and source, too
+
+ // The new node is part of the boundary only if both its neighbors are boundary nodes and the boundray proceeds from first to second.
+ new_node->boundary = (e.first->BoundaryP() && e.first->BoundaryP()) && ((findNextBoundaryNode(e.first))->Index() == e.second->Index());
+ new_node->fixed = e.first->fixed && e.second->fixed;
+ new_node->sam = new_node->boundary && (e.first->sam || e.second->sam);
+
+ // insert it into the boundary polygon;
+ /* if (new_node->boundary) {
+
+ // find the position of the first node in the boundary
+ list::iterator ins_pos = find
+ (boundary_polygon->nodes.begin(),
+ boundary_polygon->nodes.end(),
+ e.first);
+ // ... second node comes before or after it ...
+ if (*(++ins_pos!=boundary_polygon->nodes.end()?
+ ins_pos:boundary_polygon->nodes.begin())!=e.second) {
+
+ boundary_polygon->nodes.insert(((ins_pos--)!=boundary_polygon->nodes.begin()?ins_pos:(--boundary_polygon->nodes.end())), new_node);
+
+ // .. set the neighbors of the new node ...
+ // in this case e.second and e.first are inverted
+ new_node->owners.push_back( Neighbor(boundary_polygon, e.second, e.first ) );
+ //cerr << "pushing back " << Neighbor(boundary_polygon->index, e.second, e.first ) << endl;
+ } else {
+ // insert before second node, so leave ins_pos as it is,
+ // that is incremented
+ boundary_polygon->nodes.insert(ins_pos, new_node);
+
+ // .. set the neighbors of the new node ...
+ new_node->owners.push_back( Neighbor(boundary_polygon, e.first, e.second ) );
+ // cerr << "pushing back " << Neighbor(boundary_polygon->index, e.second, e.first ) << endl;
+ }
+
+ }*/
+
+
+ list owners;
+
+ // push all cells owning the two nodes of the divided edges
+ // onto a list
+ copy(e.first->owners.begin(),
+ e.first->owners.end(),
+ back_inserter(owners));
+ copy(e.second->owners.begin(),
+ e.second->owners.end(),
+ back_inserter(owners));
+
+ //copy(owners.begin(), owners.end(), ostream_iterator(cerr, " "));
+ //cerr << endl;
+
+ // sort the nodes
+ owners.sort( mem_fun_ref( &Neighbor::Cmp ) );
+
+ // extern ofstream debug_stream;
+
+ // debug_stream << "Nodes " << e.first << " and " << e.second << endl;
+ // copy(owners.begin(), owners.end(), ostream_iterator(debug_stream, " "));
+ // debug_stream << endl;
+
+ // the duplicates in this list indicate cells owning this edge
+ list::iterator c=owners.begin();
+ while (c!=owners.end()) {
+ c=adjacent_find(c,owners.end(), neighbor_cell_eq);
+
+
+ if (c!=owners.end()) { // else break;
+
+ // debug_stream << "Cell " << c->cell << " owns Edge " << e << endl;
+
+ //if (c->cell>=0) {
+ //if (!c->cell->BoundaryPolP()) {
+ // find the position of the edge's first node in cell c...
+ list::iterator ins_pos = find
+ (c->cell->nodes.begin(),
+ c->cell->nodes.end(),
+ e.first);
+ // ... second node comes before or after it ...
+
+ // XXXX probably this test is always false XXXX: No, works okay.
+ if (*(++ins_pos!=c->cell->nodes.end()?
+ ins_pos:c->cell->nodes.begin())!=e.second) {
+ c->cell->nodes.insert(((ins_pos--)!=c->cell->nodes.begin()?ins_pos:(--c->cell->nodes.end())), new_node);
+ //cells[c->cell].nodes.insert(--ins_pos, new_node->index);
+ // .. set the neighbors of the new node ...
+ // in this case e.second and e.first are inverted
+ // cerr << "Inverted\n";
+ new_node->owners.push_back( Neighbor(c->cell, e.second, e.first ) );
+ } else {
+ // insert before second node, so leave ins_pos as it is,
+ // that is incremented
+ c->cell->nodes.insert(ins_pos, new_node);
+ // .. set the neighbors of the new node ...
+ // cerr << "Not inverted\n";
+ new_node->owners.push_back( Neighbor(c->cell, e.first, e.second ) );
+ }
+
+ // redo the neighbors:
+ //}
+
+
+ // - find cell c among owners of Node e.first
+ list::iterator cpos=
+ find_if( e.first->owners.begin(),
+ e.first->owners.end(),
+ bind2nd( mem_fun_ref(&Neighbor::CellEquals), c->cell->Index()) );
+
+ // - correct the record
+ if (cpos->nb1 == e.second) {
+ cpos->nb1 = new_node;
+ } else
+ if (cpos->nb2 == e.second) {
+ cpos->nb2 = new_node;
+ }
+
+ // - same for Node e.second
+ cpos=
+ find_if( e.second->owners.begin(),
+ e.second->owners.end(),
+ bind2nd( mem_fun_ref(&Neighbor::CellEquals), c->cell->Index()) );
+
+ // - correct the record
+ if (cpos->nb1 == e.first) {
+ cpos->nb1 = new_node;
+ } else
+ if (cpos->nb2 == e.first) {
+ cpos->nb2 = new_node;
+ }
+
+
+ } else break;
+ c++;
+ }
+
+ // Repair neighborhood lists in a second loop, to make sure all
+ // `administration' is up to date
+ while (c!=owners.end()) {
+ c=adjacent_find(c,owners.end(), neighbor_cell_eq);
+ // repair neighborhood lists of cell and Wall lists
+ //if (c->cell>=0) {
+ if (!c->cell->BoundaryPolP()) {
+ c->cell->ConstructNeighborList();
+ // debug_stream << "Repairing NeighborList of " << c->cell << endl;
+ }
+ c++;
+ }
+ // debug_stream.flush();
+
+}
+
+
+/*
+ Calculate circumcircle of triangle (x1,y1), (x2,y2), (x3,y3)
+ The circumcircle centre is returned in (xc,yc) and the radius in r
+ NOTE: A point on the edge is inside the circumcircle
+*/
+void Mesh::CircumCircle(double x1,double y1,double x2,double y2,double x3,double y3,
+ double *xc,double *yc,double *r)
+{
+ double m1,m2,mx1,mx2,my1,my2;
+ double dx,dy,rsqr;
+
+ /* Check for coincident points */
+ /*if (abs(y1-y2) < TINY && abs(y2-y3) < TINY)
+ return(false);*/
+
+ if (abs(y2-y1) < TINY) {
+ m2 = - (x3-x2) / (y3-y2);
+ mx2 = (x2 + x3) / 2.0;
+ my2 = (y2 + y3) / 2.0;
+ *xc = (x2 + x1) / 2.0;
+ *yc = m2 * (*xc - mx2) + my2;
+ } else if (abs(y3-y2) < TINY) {
+ m1 = - (x2-x1) / (y2-y1);
+ mx1 = (x1 + x2) / 2.0;
+ my1 = (y1 + y2) / 2.0;
+ *xc = (x3 + x2) / 2.0;
+ *yc = m1 * (*xc - mx1) + my1;
+ } else {
+ m1 = - (x2-x1) / (y2-y1);
+ m2 = - (x3-x2) / (y3-y2);
+ mx1 = (x1 + x2) / 2.0;
+ mx2 = (x2 + x3) / 2.0;
+ my1 = (y1 + y2) / 2.0;
+ my2 = (y2 + y3) / 2.0;
+ *xc = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
+ *yc = m1 * (*xc - mx1) + my1;
+ }
+
+ dx = x2 - *xc;
+ dy = y2 - *yc;
+ rsqr = dx*dx + dy*dy;
+ *r = sqrt(rsqr);
+
+ return;
+ // Suggested
+ // return((drsqr <= rsqr + EPSILON) ? TRUE : FALSE);
+
+}
+
+//
+
+// return the total amount of chemical "ch" in the leaf
+double Mesh::SumChemical(int ch) {
+
+ double sum=0.;
+ for (vector::iterator i=cells.begin();
+ i!=cells.end();
+ i++) {
+
+ sum+=(*i)->chem[ch];
+ }
+ return sum;
+
+}
+
+
+
+void Mesh::CleanUpCellNodeLists(void) {
+
+ typedef vector ::iterator> CellItVect;
+
+ CellItVect cellstoberemoved;
+ vector cellind;
+
+ // Start of by removing all stale walls.
+ //DeleteLooseWalls();
+ // collect all dead cells that need to be removed from the simulation
+ for (vector::iterator i=cells.begin();
+ i!=cells.end();
+ i++) {
+
+ if ((*i)->DeadP()) {
+ // collect the iterators
+ cellstoberemoved.push_back(i);
+
+ // collect the indices
+ cellind.push_back((*i)->index);
+ } else {
+ // Remove pointers to dead Walls
+ for (list::iterator w=(*i)->walls.begin();
+ w!=(*i)->walls.end();
+ w++) {
+ if ((*w)->DeadP()) {
+ (*w)=0;
+ }
+ }
+ (*i)->walls.remove(0);
+ }
+ }
+
+ // Remove pointers to dead Walls from BoundaryPolygon
+ for (list::iterator w=boundary_polygon->walls.begin();
+ w!=boundary_polygon->walls.end();
+ w++) {
+ if ((*w)->DeadP()) {
+ (*w)=0;
+ }
+ }
+ boundary_polygon->walls.remove(0);
+
+
+ // Renumber cells; this is most efficient if the list of dead cell indices is sorted
+ sort(cellind.begin(),cellind.end());
+
+
+ // Reindexing of Cells
+ for (vector::reverse_iterator j=cellind.rbegin();
+ j!=cellind.rend();
+ j++) {
+
+ for (vector::reverse_iterator i=cells.rbegin();
+ i!=cells.rend();
+ i++) {
+
+ if (*j < (*i)->index) (*i)->index--;
+
+ }
+
+ }
+
+
+ // Actual deleting of Cells
+ // We must delete in reverse order, otherwise the iterators become redefined
+ for ( CellItVect::reverse_iterator i=cellstoberemoved.rbegin();
+ i!=cellstoberemoved.rend();
+ i++) {
+ Cell::NCells()--;
+ cells.erase(*i);
+ }
+
+
+ // same for nodes
+ typedef vector ::iterator> NodeItVect;
+
+ NodeItVect nodestoberemoved;
+ vector nodeindlist;
+
+ // collect iterators and indices of dead nodes
+ for (vector::iterator i=nodes.begin();
+ i!=nodes.end();
+ i++) {
+
+ if ((*i)->DeadP()) {
+ nodestoberemoved.push_back( i );
+ nodeindlist.push_back((*i)->index);
+
+ }
+ }
+
+ // sort the list of dead nodes for renumbering
+ sort(nodeindlist.begin(),nodeindlist.end());
+
+
+ // Reindicing of Nodes
+ for (vector::reverse_iterator j=nodeindlist.rbegin();
+ j!=nodeindlist.rend();
+ j++) {
+
+ for (vector::reverse_iterator i=nodes.rbegin();
+ i!=nodes.rend();
+ i++) {
+
+ if (*j < (*i)->index) {
+
+ (*i)->index--;
+ }
+
+
+ }
+
+ }
+
+ // Actual deleting of nodes
+ // We must delete in reverse order, otherwise the iterators become redefined
+ for ( NodeItVect::reverse_iterator i=nodestoberemoved.rbegin();
+ i!=nodestoberemoved.rend();
+ i++) {
+ Node::nnodes--;
+ nodes.erase(*i);
+ }
+
+
+
+ for (list::iterator w=walls.begin();
+ w!=walls.end();
+ w++) {
+ if ((*w)->DeadP()) {
+ Wall::nwalls--;
+ delete *w;
+ *w = 0;
+ }
+ }
+
+ walls.remove( 0 );
+
+
+
+ // Clean up all intercellular connections and redo everything
+ for (vector::iterator i=nodes.begin();
+ i!=nodes.end();
+ i++) {
+
+ (*i)->owners.clear();
+ }
+
+ for (vector::iterator i=cells.begin();
+ i!=cells.end();
+ i++) {
+
+ (*i)->ConstructConnections();
+
+ }
+
+ boundary_polygon->ConstructConnections();
+
+ /* for (list::iterator w=walls.begin();
+ w!=walls.end();
+ w++) {
+ delete *w;
+ }
+
+ walls.clear();
+ cerr << "Cleared walls\n";
+ for (vector::iterator i=cells.begin();
+ i!=cells.end();
+ i++) {
+
+ (*i)->ConstructWalls();
+ }
+ */
+
+ // remake shuffled_nodes and shuffled cells
+ shuffled_nodes.clear();
+ shuffled_nodes = nodes;
+
+ shuffled_cells.clear();
+ shuffled_cells = cells;
+
+}
+
+void Mesh::CutAwayBelowLine( Vector startpoint, Vector endpoint) {
+
+ // Kills all cells below the line startpoint -> endpoint
+
+ Vector perp = (endpoint-startpoint).Perp2D().Normalised();
+
+
+ cerr << "Before Apoptose\n";
+ TestIllegalWalls();
+ for (vector::iterator i=cells.begin();
+ i!=cells.end();
+ i++) {
+
+ // do some vector geometry to check whether the cell is below the cutting line
+ Vector cellvec = ((*i)->Centroid()-startpoint);
+
+ if ( InnerProduct(perp, cellvec) < 0 ) {
+ // remove those cells
+ (*i)->Apoptose();
+ }
+ }
+
+ cerr << "Before CleanUpCellNodeLists\n";
+ TestIllegalWalls();
+
+ CleanUpCellNodeLists();
+
+}
+
+void Mesh::CutAwaySAM(void) {
+
+ for (vector::iterator i=cells.begin();
+ i!=cells.end();
+ i++) {
+
+ if( (*i)->Boundary() == Cell::SAM ) {
+
+ (*i)->Apoptose();
+ }
+ }
+
+ TestIllegalWalls();
+
+ CleanUpCellNodeLists();
+
+
+}
+void Mesh::TestIllegalWalls(void) {
+
+ for (list::iterator w = walls.begin();
+ w!=walls.end();
+ w++) {
+ if ((*w)->IllegalP() ) {
+ cerr << "Wall " << **w << " is illegal.\n";
+ }
+ }
+
+}
+
+
+
+class node_owners_eq : public unary_function {
+ int no;
+public:
+
+ explicit node_owners_eq(int nn) { no=nn; }
+
+ bool operator() (const Node &n) const {
+ if (n.CellsSize()==1)
+ return true;
+ else
+ return false;
+ }
+
+};
+
+
+void Mesh::RepairBoundaryPolygon(void) {
+
+ // After serious manipulations (e.g. after cutting part off the
+ // leaf) repair the boundary polygon. It assumes the cut line has
+ // already been marked "boundary" and the original boundary marks
+ // were not removed.
+ //
+ // So, this function just puts boundary nodes into the boundary
+ // polygon in the right order; it cannot detect boundaries from
+ // scratch.
+
+ Node *boundary_node=0, *next_boundary_node=0, *internal_node;
+ set original_boundary_nodes, repaired_boundary_nodes;
+ vector difference; // set difference result
+
+ // Step 0: print out current boundary polygon
+#ifdef QDEBUG
+ qDebug() << endl << "Original Boundary Polygon node indices: ";
+ foreach (Node* node, boundary_polygon->nodes) {
+ qDebug() << node->Index() << " " ;
+ }
+ qDebug() << endl << endl;
+#endif
+
+ // Step 1a: Create a set containing the current boundary polygon nodes' Indices.
+ foreach (Node* node, boundary_polygon->nodes) {
+ original_boundary_nodes.insert(node->Index());
+ }
+
+ // Step 1b: remove all nodes from boundary polygon
+ boundary_polygon->nodes.clear();
+
+ // Step 2: Remove all references to the boundary polygon from the Mesh's current list of nodes
+ foreach (Node* node, nodes) {
+ node->Unmark(); // remove marks, we need them to determine if we have closed the circle
+ list::iterator boundary_ref_pos;
+ if ((boundary_ref_pos = find_if (node->owners.begin(), node->owners.end(),
+ bind2nd(mem_fun_ref(&Neighbor::CellEquals), -1))) != node->owners.end()) {
+ // i.e. if one of the node's owners is the boundary polygon
+ node->owners.erase(boundary_ref_pos); // remove the reference
+ }
+ }
+
+ // Step 3: Search for the first boundary node. We reconstruct the
+ // boundary polygon by moving along the boundary nodes until we've
+ // encircled the polygon. Since manually adding nodes may have
+ // turned nodes previously along the boundary into internal nodes,
+ // we search through all the node until we find first boundary node
+ // and proceed from there. If findNextBoundaryNode() returns a node
+ // other than the one passed to it, the original node is the first
+ // boundary node.
+ foreach (Node* node, nodes) {
+ if ((findNextBoundaryNode(node))->index != node->index){
+ next_boundary_node = node;
+ break;
+ }
+ }
+
+ // We have a problem if we arrive here without having found a boundary node.
+ if (!next_boundary_node) throw("Cannot find a boundary node!.");
+
+ // Reconstruct the list of boundary polygon nodes.
+ do {
+ boundary_node = next_boundary_node;
+ boundary_node->Mark();
+ boundary_polygon->nodes.push_back(boundary_node);
+ next_boundary_node = findNextBoundaryNode(boundary_node);
+ } while ( !next_boundary_node->Marked() );
+
+
+ // Create a set containing the reconstructed boundary polygon nodes' Indices.
+ for (list::iterator it = boundary_polygon->nodes.begin(); it!=boundary_polygon->nodes.end(); ++it) {
+ repaired_boundary_nodes.insert((*it)->Index());
+ }
+
+ // Calculate the difference between the original and repaired sets of boundary nodes
+ // yielding the set of nodes that are no longer part of the boundary polygon.
+ set_difference(original_boundary_nodes.begin(), original_boundary_nodes.end(),
+ repaired_boundary_nodes.begin(), repaired_boundary_nodes.end(), back_inserter(difference));
+
+ // Tell each node in the difference that it's no longer part of the boundary polygon
+ vector::iterator internal_node_it;
+ foreach (int i, difference){
+ internal_node_it = find_if (nodes.begin(), nodes.end(), bind2nd(mem_fun(&Node::IndexEquals), i));
+ internal_node = *internal_node_it; // dereference the itterator to get to the node pointer
+ if (!internal_node) throw("Found a null Node pointer.");
+ internal_node->UnsetBoundary();
+ }
+
+ boundary_polygon->ConstructConnections();
+ for (list::iterator w=boundary_polygon->walls.begin();
+ w!=boundary_polygon->walls.end();
+ w++) {
+ if ((*w)->DeadP()) {
+ (*w)=0;
+ }
+ }
+ boundary_polygon->walls.remove(0);
+ boundary_polygon->ConstructNeighborList();
+
+#ifdef QDEBUG
+ cerr << "Repaired Boundary Polygon node indices: ";
+ foreach (Node* node, boundary_polygon->nodes){
+ qDebug() << node->Index() << " " ;
+ }
+ qDebug() << endl ;
+
+ #ifdef _undefined_
+ qDebug() << "NODES:" << endl;
+ foreach(Node* node, nodes) {
+ qDebug() << *node;
+ }
+ qDebug() << endl;
+
+ qDebug() << "WALLS:" << endl;
+ foreach(Wall* wall, walls) {
+ qDebug() << *wall;
+ }
+ qDebug() << endl;
+
+ qDebug() << "CELLS:" << endl;
+ foreach(Cell* cell, cells) {
+ qDebug() << *cell;
+ }
+ qDebug() << endl;
+ #endif
+#endif
+
+}
+
+
+Node* Mesh::findNextBoundaryNode(Node* boundary_node) {
+ bool found_next_boundary_node = false;
+ Node *next_boundary_node;
+ set boundary_node_owners; // This is a list of the current boundary node's owners' Ids
+ vector neighborIds; // A list of the current boundary node's owners' 2nd neighbor Ids
+ vector *> nodeOwners; // A vector of set pointers where each set contains the owner Ids of the nodes in the neighborIds list.
+ vector intersection; // set intersection result
+
+ // The next boundary node is that which has only one owner in common with the current boundary node
+ for (list::iterator it=boundary_node->owners.begin(); it!=boundary_node->owners.end(); ++it) {
+ if (it->cell->Index() != -1) boundary_node_owners.insert(it->cell->Index()); // Save each of the current boundary node's owners' Ids - except the boundary polygon
+ set *owners = new set; // create a set to hold a 2nd neighbor's owners' Ids
+ nodeOwners.push_back(owners);
+ neighborIds.push_back(it->nb2->Index());
+ foreach(Neighbor neighbor, it->nb2->owners){
+ if (neighbor.cell->Index() != -1) owners->insert(neighbor.cell->Index()); // Save second neighbors' owners' Ids - except the boundary polygon
+ }
+ }
+ vector::iterator itt = neighborIds.begin();
+ vector *>::iterator it = nodeOwners.begin();
+
+ #ifdef QDEBUG
+ qDebug() << "Boundary node: " << boundary_node->Index() << " is owned by the following cells: ";
+ foreach (int i, boundary_node_owners){
+ qDebug() << i << " ";
+ }
+ qDebug() << endl;
+ #endif
+
+ for (; it < nodeOwners.end(); it++, itt++) {
+ intersection.clear();
+ set_intersection(boundary_node_owners.begin(), boundary_node_owners.end(), (*it)->begin(), (*it)->end(), back_inserter(intersection));
+
+ #ifdef QDEBUG
+ qDebug() << "The intersection of the boundary node(" << boundary_node->Index() << ") owners and its 2nd neighbor(" << *itt << ") owners is: ";
+ foreach (int i, intersection){
+ qDebug() << i << " ";
+ }
+ qDebug() << endl;
+ #endif
+
+ if (intersection.size() == 1){
+ found_next_boundary_node = true;
+ vector::iterator next_boundary_node_it = find_if (nodes.begin(), nodes.end(), bind2nd(mem_fun(&Node::IndexEquals), *itt));
+ next_boundary_node = *next_boundary_node_it; // defeference the itterator to get to the node pointer
+
+ #ifdef QDEBUG
+ qDebug() << "The Current boundary node is: " << boundary_node->Index()
+ << ". The Next boundary node is: " << *itt << ((next_boundary_node->Marked()) ? " Marked" : " Unmarked") << endl << endl;
+ #endif
+
+ break;
+ }
+ }
+
+ #ifdef QDEBUG
+ if (!found_next_boundary_node) {
+ qDebug() << "OOPS! Didn't find the next boundrary node!" << endl;
+ }
+ #endif
+
+ return next_boundary_node;
+}
+
+
+void Mesh::CleanUpWalls(void) {
+ for (list::iterator w=walls.begin();
+ w!=walls.end();
+ w++) {
+
+ if ((*w)->DeadP()) {
+ delete *w;
+ (*w)=0;
+ }
+ }
+ walls.remove(0);
+}
+
+void Mesh::Rotate(double angle, Vector center) {
+
+ // Rotate the mesh over the angle "angle", relative to center point "center".
+
+ Matrix rotmat;
+
+ rotmat.Rot2D(angle);
+
+ for (vector::iterator n=nodes.begin();
+ n!=nodes.end();
+ n++) {
+
+ (*n)->setPos ( rotmat * ( *(*n) - center ) + center );
+
+ }
+}
+
+
+void Mesh::PrintWallList( void ) {
+
+ transform ( walls.begin(), walls.end(), ostream_iterator(cerr, "\n"), deref_ptr );
+
+}
+
+#include
+//#include "forwardeuler.h"
+#include "rungekutta.h"
+
+class SolveMesh : public RungeKutta {
+
+private:
+ SolveMesh(void);
+
+public:
+ SolveMesh(Mesh *m_) {
+
+ m = m_;
+
+ kmax=0;
+ kount=0;
+ xp=0; yp=0; dxsav=0;
+
+
+ }
+
+protected:
+ virtual void derivs(double x, double *y, double *dydx) {
+
+ // set mesh with new values given by ODESolver
+ // (we must do this, because only mesh knows the connections
+ // between the variables)
+
+ m->setValues(x,y);
+ m->Derivatives(dydx);
+
+ /*static int c=0;
+ QString fname("derivs%1.dat");
+
+ ofstream of(fname.arg(++c).ascii());
+
+ for (int i=0;iNEqs();i++) {
+ of << x << " " << dxdy[i] << endl;
+ }
+ of.close();
+ */
+
+ //cerr << "Calculated derivatives at " << x << "\n";
+ }
+
+private:
+ Mesh *m;
+ int kmax,kount;
+ double *xp,**yp,dxsav;
+ bool monitor_window;
+};
+
+
+
+void Mesh::ReactDiffuse(double delta_t) {
+
+ // Set Lengths of Walls
+ for_each ( walls.begin(), walls.end(),
+ mem_fun( &Wall::SetLength ) );
+
+ static SolveMesh *solver = new SolveMesh(this);
+
+ int nok, nbad, nvar;
+ double *ystart = getValues(&nvar);
+
+ solver->odeint(ystart, nvar, getTime(), getTime() + delta_t,
+ par.ode_accuracy, par.dt, 1e-10, &nok, &nbad);
+
+ setTime(getTime()+delta_t);
+ setValues(getTime(),ystart);
+
+}
+
+
+Vector Mesh::FirstConcMoment(int chem) {
+
+ Vector moment;
+ for (vector::const_iterator c=cells.begin();
+ c!=cells.end();
+ c++) {
+
+ moment += (*c)->Chemical(chem) * (*c)->Centroid();
+
+ }
+
+ return moment / (double)cells.size();
+}
+
+/*! This member function deletes all walls connected to two dead cells from the mesh.
+ It should be called before the Cells are actually removed.
+ If the cell is connect to one dead cell only, that reference is substituted for a reference
+ to the boundary polygon.
+*/
+void Mesh::DeleteLooseWalls(void) {
+
+ list::iterator w=walls.begin();
+
+ while (w!=walls.end()) {
+
+ // if both cells of the wall are dead, remove the wall
+ if ((*w)->C1()->DeadP() || (*w)->C2()->DeadP()) {
+ if ((*w)->C1()->DeadP() && (*w)->C2()->DeadP()) {
+ delete *w;
+ w=walls.erase(w);
+ } else {
+ if ((*w)->C1()->DeadP())
+ (*w)->c1 = boundary_polygon;
+ else
+ (*w)->c2 = boundary_polygon;
+ w++;
+ }
+ } else {
+ w++;
+ }
+
+ }
+
+}
+
+/*void Mesh::FitLeafToCanvas(double width, double height) {
+
+ Vector bbll,bbur;
+ BoundingBox(bbll,bbur);
+
+ double scale_x = width/(bbur.x-bbll.x);
+ double scale_y = height/(bbur.y-bbll.y);
+
+ double factor = scale_x &clean_chem, const vector &clean_transporters) {
+
+ if (clean_chem.size()!=(unsigned)Cell::NChem() || clean_transporters.size()!=(unsigned)Cell::NChem()) {
+ throw "Run time error in Mesh::CleanChemicals: size of clean_chem and clean_transporters should be equal to Cell::NChem()";
+ }
+ for (vector::iterator c=cells.begin();
+ c!=cells.end();
+ c++) {
+
+ for (int i=0;iSetChemical(i,clean_chem[i]);
+ }
+ (*c)->SetNewChemToChem();
+
+ }
+
+ // clean transporters
+ for (list::iterator w=walls.begin();
+ w!=walls.end();
+ w++) {
+
+ for (int i=0;isetTransporters1(i,clean_transporters[i]); (*w)->setNewTransporters1(i,clean_transporters[i]);
+ (*w)->setTransporters2(i,clean_transporters[i]); (*w)->setNewTransporters2(i,clean_transporters[i]);
+ }
+ }
+
+}
+
+void Mesh::RandomizeChemicals(const vector &max_chem, const vector &max_transporters) {
+
+ if (max_chem.size()!=(unsigned)Cell::NChem() || max_transporters.size()!=(unsigned)Cell::NChem()) {
+ throw "Run time error in Mesh::CleanChemicals: size of max_chem and max_transporters should be equal to Cell::NChem()";
+ }
+
+ for (vector::iterator c=cells.begin();
+ c!=cells.end();
+ c++) {
+
+ for (int i=0;iSetChemical(i,max_chem[i]*RANDOM());
+ }
+ (*c)->SetNewChemToChem();
+
+ }
+
+ // randomize transporters
+ for (list::iterator w=walls.begin();
+ w!=walls.end();
+ w++) {
+
+ for (int i=0;isetTransporters1(i,max_transporters[i] * RANDOM()); (*w)->setNewTransporters1(i, (*w)->Transporters1(i) );
+ (*w)->setTransporters2(i,max_transporters[i] * RANDOM()); (*w)->setNewTransporters2(i, (*w)->Transporters1(i) );
+ }
+ }
+
+}
+
+//!\brief Calculates a vector with derivatives of all variables, which
+// we can pass to an ODESolver.
+void Mesh::Derivatives(double *derivs) {
+
+ int nwalls = walls.size();
+ int ncells = cells.size();
+ int nchems = Cell::NChem();
+
+ // two eqs per chemical for each walls, and one eq per chemical for each cell
+ // This is for generality. For a specific model you may optimize
+ // this by removing superfluous (empty) equations.
+ int neqs = 2 * nwalls * nchems + ncells * nchems;
+
+ //static double *derivs = 0;
+ // derivs is allocated by RungeKutta class.
+
+ for (int i=0;i::iterator c=cells.begin();
+ c!=cells.end();
+ c++) {
+ //(*cr)(*c, &(derivs[i]));
+ plugin->CellDynamics(*c, &(derivs[i]));
+ i+=nchems;
+ }
+
+ for (list::iterator w=walls.begin();
+ w!=walls.end();
+ w++) {
+ // (*wr)(*w, &(derivs[i]), &(derivs[i+nchems]));
+ plugin->WallDynamics(*w, &(derivs[i]), &(derivs[i+nchems]));
+ // Transport function adds to derivatives of cell chemicals
+ plugin->CelltoCellTransport(*w, &(derivs[(*w)->c1->Index() * nchems]),
+ &(derivs[(*w)->c2->Index() * nchems]));
+
+ //(*tf)(*w, &(derivs[(*w)->c1->Index() * nchems]),
+ //&(derivs[(*w)->c2->Index() * nchems] ) );
+ i+=2*nchems;
+ }
+
+
+}
+
+void Mesh::setValues(double x, double *y) {
+
+ //int nwalls = walls.size();
+ //int ncells = cells.size();
+ int nchems = Cell::NChem();
+
+ // two eqs per chemical for each walls, and one eq per chemical for each cell
+ // This is for generality. For a specific model you may optimize
+ // this by removing superfluous (empty) equations.
+ //int neqs = 2 * nwalls * nchems + ncells * nchems;
+
+ // Layout of derivatives: cells [ chem1 ... chem n] walls [ [ w1(chem 1) ... w1(chem n) ] [ w2(chem 1) ... w2(chem n) ] ]
+
+ int i=0;
+ static int emit_count=0;
+ const int stride = 100;
+ for (vector::iterator c=cells.begin();
+ c!=cells.end();
+ c++) {
+ for (int ch=0;chSetChemical(ch, y[i+ch]);
+ }
+ if ( !(emit_count%stride)) {
+ (*c)->EmitValues(x);
+ }
+ i+=nchems;
+ }
+
+ for (list::iterator w=walls.begin();
+ w!=walls.end();
+ w++) {
+
+ for (int ch=0;chsetTransporters1(ch,y[i+ch]);
+ }
+ i+=nchems;
+
+ for (int ch=0;chsetTransporters2(ch,y[i+ch]);
+ }
+ i+=nchems;
+
+ }
+
+ emit_count++;
+}
+
+double *Mesh::getValues(int *neqs) {
+
+ int nwalls = walls.size();
+ int ncells = cells.size();
+ int nchems = Cell::NChem();
+
+ // two eqs per chemical for each wall, and one eq per chemical for each cell
+ // This is for generality. For a specific model you may optimize
+ // this by removing superfluous (empty) equations.
+ (*neqs) = 2 * nwalls * nchems + ncells * nchems;
+
+ // Layout of derivatives: cells [ chem1 ... chem n] walls [ [ w1(chem 1) ... w1(chem n) ] [ w2(chem 1) ... w2(chem n) ] ]
+
+ static double *values = 0;
+ if (values!=0) { delete[] values; }
+
+ values = new double[*neqs];
+
+ int i=0;
+ for (vector::iterator c=cells.begin();
+ c!=cells.end();
+ c++) {
+ for (int ch=0;chChemical(ch);
+ }
+ i+=nchems;
+ }
+
+ for (list::iterator w=walls.begin();
+ w!=walls.end();
+ w++) {
+
+ for (int ch=0;chTransporters1(ch);
+ }
+ i+=nchems;
+
+ for (int ch=0;chTransporters2(ch);
+ }
+ i+=nchems;
+
+ }
+
+ return values;
+}
+
+void Mesh::DrawNodes(QGraphicsScene *c) const {
+
+ for (vector::const_iterator n=nodes.begin();
+ n!=nodes.end();
+ n++) {
+
+ Node *i=*n;
+
+ NodeItem *item = new NodeItem ( &(*i), c );
+ item->setColor();
+
+ item->setZValue(5);
+ item->show();
+ item ->setPos(((Cell::offset[0]+i->x)*Cell::factor),
+ ((Cell::offset[1]+i->y)*Cell::factor) );
+ }
+
+}
+
+/*! Returns the sum of protein "ch" of a cycling protein in cells and walls */
+double Mesh::CalcProtCellsWalls(int ch) const {
+
+
+ double sum_prot=0.;
+
+ // At membranes
+ for (list::const_iterator w=walls.begin();
+ w!=walls.end();
+ w++) {
+ sum_prot += (*w)->Transporters1(ch);
+ sum_prot += (*w)->Transporters2(ch);
+ }
+
+ // At cells
+ for (vector::const_iterator c=cells.begin();
+ c!=cells.end();
+ c++) {
+
+ sum_prot += (*c)->Chemical(ch);
+ }
+
+ return sum_prot;
+
+}
+
+void Mesh::SettoInitVals(void) {
+
+ vector clean_chem(Cell::NChem());
+ vector clean_transporters(Cell::NChem());
+
+ for (int i=0;i Mesh::VertexAngles(void) {
+ QVector angles;
+ for (vector::const_iterator n=nodes.begin();
+ n!=nodes.end();
+ n++) {
+ if ((*n)->Value()>2 && !(*n)->BoundaryP() ) {
+ angles+=(*n)->NeighbourAngles();
+ }
+ }
+ return angles;
+}
+
+QVector< QPair > Mesh::VertexAnglesValues(void) {
+
+ QVector< QPair > anglesvalues;
+ for (vector::const_iterator n=nodes.begin();
+ n!=nodes.end();
+ n++) {
+ if ((*n)->Value()>2 && !(*n)->BoundaryP() ) {
+
+ QVector angles = (*n)->NeighbourAngles();
+ int value_vertex = angles.size();
+ for (QVector::ConstIterator i=angles.begin();
+ i!=angles.end();
+ i++) {
+
+ anglesvalues += QPair< qreal, int > (*i, value_vertex);
+ }
+ }
+ }
+ return anglesvalues;
+}
+
+void Mesh::Clean(void) {
+ #ifdef QDEBUG
+ qDebug() << "Freeing nodes" << endl;
+ #endif
+ for (vector::iterator i=nodes.begin();
+ i!=nodes.end();
+ i++) {
+ delete *i;
+ }
+ nodes.clear();
+ Node::nnodes=0;
+
+ #ifdef QDEBUG
+ qDebug() << "Freeing node sets" << endl;
+ #endif
+ for (vector::iterator i=node_sets.begin();
+ i!=node_sets.end();
+ i++) {
+ delete *i;
+ }
+ node_sets.clear();
+
+
+ #ifdef QDEBUG
+ qDebug() << "Freeing cells" << endl;
+ #endif
+ //CellsStaticDatamembers *old_static_data_mem = Cell::GetStaticDataMemberPointer();
+ for (vector::iterator i=cells.begin();
+ i!=cells.end();
+ i++) {
+ delete *i;
+ }
+ //Cell::static_data_members = old_static_data_mem;
+
+ cells.clear();
+ Cell::NCells()=0;
+
+ delete boundary_polygon; // (already deleted during cleaning of cells?)
+
+ #ifdef QDEBUG
+ qDebug() << "Freeing walls" << endl;
+ #endif
+ for (list::iterator i=walls.begin();
+ i!=walls.end();
+ i++) {
+ delete *i;
+ }
+ walls.clear();
+ Wall::nwalls=0;
+
+ node_insertion_queue.clear();
+ shuffled_nodes.clear();
+ shuffled_cells.clear();
+ time = 0.0;
+}
+
+void Mesh::StandardInit(void) {
+
+ boundary_polygon = new BoundaryPolygon();
+ Cell &circle=CircularCell(0,0,10,10);
+
+ circle.SetTargetArea(circle.CalcArea());
+ circle.SetTargetLength(par.target_length);
+ circle.SetLambdaLength(par.lambda_celllength);
+ SetBaseArea();
+ // clean up chemicals
+ for (int c=0; c | | | | | | | | | | | | | | | | | | | | |