Changeset - 782330072e62
[Not reviewed]
default
0 91 0
Michael Guravage - 15 years ago 2010-06-17 18:13:46
michael.guravage@cwi.nl
Reformatted the source files and generally straighten up the code.

--
user: Michael Guravage <michael.guravage@cwi.nl>
branch 'default'

changed src/Neighbor.cpp
changed src/Neighbor.h
changed src/OptionFileDialog.cpp
changed src/OptionFileDialog.h
changed src/UniqueMessage.cpp
changed src/UniqueMessage.h
changed src/VirtualLeaf.cpp
changed src/apoplastitem.cpp
changed src/apoplastitem.h
changed src/build_models/auxingrowthplugin.cpp
changed src/build_models/auxingrowthplugin.h
changed src/build_models/meinhardtplugin.cpp
changed src/build_models/meinhardtplugin.h
changed src/build_models/testplugin.cpp
changed src/build_models/testplugin.h
changed src/build_models/translate_plugin.pl
changed src/canvas.cpp
changed src/canvas.h
changed src/cell.cpp
changed src/cell.h
changed src/cellbase.cpp
changed src/cellbase.h
changed src/cellitem.cpp
changed src/cellitem.h
changed src/curvecolors.h
changed src/data_plot.cpp
changed src/data_plot.h
changed src/far_mem_5.h
changed src/flux_function.h
changed src/forwardeuler.cpp
changed src/forwardeuler.h
changed src/infobar.h
changed src/mainbase.cpp
changed src/mainbase.h
changed src/matrix.cpp
changed src/matrix.h
changed src/maxmin.h
changed src/mesh.cpp
changed src/mesh.h
changed src/miscq.cpp
changed src/miscq.h
changed src/modelcatalogue.cpp
changed src/modelcatalogue.h
changed src/modelelement.h
changed src/node.cpp
changed src/node.h
changed src/nodeitem.cpp
changed src/nodeitem.h
changed src/nodeset.cpp
changed src/nodeset.h
changed src/output.cpp
changed src/output.h
changed src/parameter.cpp
changed src/parameter.h
changed src/pardialog.cpp
changed src/pardialog.h
changed src/parse.cpp
changed src/parse.h
changed src/perl/deployapp.pl
changed src/perl/histogram.pl
changed src/perl/make_parameter_source.pl
changed src/perl/make_pardialog_source.pl
changed src/perl/make_xmlwritecode.pl
changed src/pi.h
changed src/qcanvasarrow.h
changed src/random.cpp
changed src/random.h
changed src/rseed.cpp
changed src/rungekutta.cpp
changed src/rungekutta.h
changed src/simitembase.cpp
changed src/simitembase.h
changed src/simplugin.cpp
changed src/simplugin.h
changed src/sqr.h
changed src/tiny.h
changed src/transporterdialog.cpp
changed src/transporterdialog.h
changed src/vector.cpp
changed src/vector.h
changed src/vleafmodel.h
changed src/wall.cpp
changed src/wall.h
changed src/wallbase.cpp
changed src/wallbase.h
changed src/wallitem.cpp
changed src/wallitem.h
changed src/warning.cpp
changed src/warning.h
changed src/xmlwrite.cpp
changed src/xmlwrite.h
91 files changed with 9270 insertions and 9461 deletions:
src/cell.cpp
1580
1636
src/cell.h
133
141
src/mesh.cpp
653
685
src/mesh.h
367
368
src/node.h
34
47
src/wall.cpp
172
181
src/wall.h
21
23
0 comments (0 inline, 0 general)
src/Neighbor.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include "Neighbor.h"
 
#include "cell.h"
 
#include <string>
 

	
 
static const std::string _module_id("$Id$");
 

	
 
Neighbor::Neighbor(void):
 
  cell(NULL), nb1(NULL), nb2(NULL){}
 

	
 
Neighbor::Neighbor(Cell *c, Node *n1, Node *n2):
 
 cell(c), nb1(n1), nb2(n2){}
 
  cell(c), nb1(n1), nb2(n2){}
 

	
 
Neighbor::Neighbor(const Neighbor &src):
 
  cell(src.cell), nb1(src.nb1), nb2(src.nb2){} // copy constructor
 
  
 

	
 
bool Neighbor::CellEquals(int i) const { return cell->Index() == i; } 
 
bool Neighbor::Cmp(Neighbor &c) const { return cell->Index() < c.cell->Index(); } // Compare cell indices not pointers.
 
bool Neighbor::Eq(Neighbor &c) const { return cell->Index() == c.cell->Index(); }
 
Cell* Neighbor::getCell(void) const { return cell; } 
 

	
 
bool neighbor_cell_eq(const Neighbor &n1, const Neighbor &n2) {
 
  return (n1.getCell())->Index() == (n2.getCell())->Index(); // Compare cell indices not pointers.
 
}
 
  
 
// finis
 

	
 
/* finis */
 

	
src/Neighbor.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _NEIGHBOR_H_
 
#define _NEIGHBOR_H_
 

	
 
#include <iostream>
 
#include <libxml/parser.h>
 
#include <libxml/tree.h>
 

	
 
using namespace std;
 

	
 
class Cell;
 
class Node;
 

	
 
class Neighbor {
 

	
 
 protected:
 
  // Proper accessors and mutators should obviate these friend classes!
 
  friend class Cell;
 
  friend class Mesh;
 
  friend class Node;
 
  friend class FigureEditor;
 

	
 
  Cell *cell;
 
  Node *nb1, *nb2;
 

	
 
 public:
 
  Neighbor(void);
 
  Neighbor(Cell*, Node*, Node*);
 
  Neighbor(const Neighbor&);
 
  
 

	
 
  bool CellEquals(int) const;
 
  bool Cmp(Neighbor&) const;
 
  bool Eq(Neighbor&) const;
 
  Cell* getCell(void) const;
 
  void XMLAdd(xmlNodePtr) const;
 

	
 
  ostream &print(ostream &os) const;
 
};
 

	
 
// Overload the << operator 
 
ostream &operator<<(ostream &os, const Neighbor &n);
 

	
 
// Realize that we're equating like pointers with object equivalence!
 
bool neighbor_cell_eq(const Neighbor &n1, const Neighbor &n2);
 

	
 
#endif
 

	
 
// finis
 
/* finis */
 

	
src/OptionFileDialog.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include "OptionFileDialog.h"
 
#include <QCheckBox>
 
#include <iostream>
 
using namespace  std; 
 

	
 
static const std::string _module_id("$Id$");
 

	
 
OptionFileDialog::OptionFileDialog(QWidget *parent, const char *name, bool modal) : Q3FileDialog(parent, name, modal) {
 
OptionFileDialog::OptionFileDialog(QWidget *parent, const char *name, bool modal) : Q3FileDialog(parent, name, modal)
 
{
 
  //cerr << "This is an OptionFileDialog\n";
 
  geometrycheck = new QCheckBox("geometry",this);
 
  geometrycheck -> setCheckState(Qt::Checked);
 

	
 
	//cerr << "This is an OptionFileDialog\n";
 
	geometrycheck = new QCheckBox("geometry",this);
 
	geometrycheck -> setCheckState(Qt::Checked);
 
	
 
	parcheck = new QCheckBox("parameters", this);
 
	parcheck -> setCheckState(Qt::Checked);
 
	
 
	addToolButton(geometrycheck);
 
	addToolButton(parcheck);
 
  parcheck = new QCheckBox("parameters", this);
 
  parcheck -> setCheckState(Qt::Checked);
 

	
 
  addToolButton(geometrycheck);
 
  addToolButton(parcheck);
 
};
 

	
 
OptionFileDialog::OptionFileDialog ( const QString & dirName, const QString & filter , QWidget * parent, const char * name , bool modal  ) :
 
		Q3FileDialog(dirName, filter, parent, name, modal) {
 
		
 
			cerr << "This is an OptionFileDialog\n";
 
					
 
	};
 
OptionFileDialog::OptionFileDialog ( const QString & dirName, const QString & filter , 
 
				     QWidget * parent, const char * name , bool modal  ) :
 
  Q3FileDialog(dirName, filter, parent, name, modal) {
 

	
 
  cerr << "This is an OptionFileDialog\n";
 
};
 

	
 
/* finis */
src/OptionFileDialog.h
Show inline comments
 
/*
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#ifndef _OPTIONFILEDIALOG_H_
 
#define _OPTIONFILEDIALOG_H_
 

	
 
#include <Q3FileDialog>
 
#include <QCheckBox>
 

	
 
class OptionFileDialog : public Q3FileDialog {
 
	Q_OBJECT
 
public:
 
	OptionFileDialog(QWidget *parent = 0, const char *name = 0, bool modal = false);
 
	OptionFileDialog ( const QString & dirName, const QString & filter = QString(), QWidget * parent = 0, const char * name = 0, bool modal = false );
 
	
 
	bool readGeometryP(void) const { return geometrycheck->checkState()==Qt::Checked; }
 
	bool readParametersP(void) const { return parcheck->checkState()==Qt::Checked; }
 
  Q_OBJECT
 
 public:
 
  OptionFileDialog(QWidget *parent = 0, const char *name = 0, bool modal = false);
 
  OptionFileDialog ( const QString & dirName, const QString & filter = QString(), 
 
		     QWidget * parent = 0, const char * name = 0, bool modal = false );
 

	
 
private:
 
	QCheckBox *geometrycheck;	
 
	QCheckBox *parcheck;
 
  bool readGeometryP(void) const { return geometrycheck->checkState()==Qt::Checked; }
 
  bool readParametersP(void) const { return parcheck->checkState()==Qt::Checked; }
 

	
 
 private:
 
  QCheckBox *geometrycheck;	
 
  QCheckBox *parcheck;
 
};
 

	
 
#endif
 

	
 
/* finis */
src/UniqueMessage.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include <QMessageBox>
 
#include <QCheckBox>
 
#include <QPushButton>
 
#include <QBoxLayout>
 
#include "UniqueMessage.h"
 

	
 
#include <iostream>
 

	
 
static const std::string _module_id("$Id$");
 

	
 
using namespace std;
 
UniqueMessageBox::UniqueMessageBox ( /* Icon icon,*/ 
 
									 const QString & title, 
 
									 const QString & text, 
 
									 QWidget * parent ,
 
									 Qt::WindowFlags f ) : 
 
QDialog(parent, f) {
 
	
 
	label = new QLabel(text);
 
	boxtext = text;
 
	
 
	show_again = new QCheckBox(tr("Do not show this message again"));
 
	okButton = new QPushButton(tr("Ok"));
 
		
 
	if (issued_messages.contains(boxtext) ) {
 
		
 
		cerr << "Saw message before\n";
 
		display = false;
 
	} else {
 
		display=true;
 
	}
 
	
 
	connect(okButton, SIGNAL(clicked()), this, SLOT(close()) );
 
	QHBoxLayout *hlayout = new QHBoxLayout;
 
	hlayout->addWidget(label);
 
	hlayout->addWidget(okButton);
 
	QVBoxLayout *layout = new QVBoxLayout;
 
	layout->addLayout(hlayout);
 
	layout->addWidget(show_again);
 
	setLayout(layout);
 
	setWindowTitle(title);
 
				    const QString & title, 
 
				    const QString & text, 
 
				    QWidget * parent ,
 
				    Qt::WindowFlags f ) : 
 
  QDialog(parent, f) {
 

	
 
  label = new QLabel(text);
 
  boxtext = text;
 

	
 
  show_again = new QCheckBox(tr("Do not show this message again"));
 
  okButton = new QPushButton(tr("Ok"));
 

	
 
  if (issued_messages.contains(boxtext) ) {
 

	
 
    cerr << "Saw message before\n";
 
    display = false;
 
  } else {
 
    display=true;
 
  }
 

	
 
  connect(okButton, SIGNAL(clicked()), this, SLOT(close()) );
 
  QHBoxLayout *hlayout = new QHBoxLayout;
 
  hlayout->addWidget(label);
 
  hlayout->addWidget(okButton);
 
  QVBoxLayout *layout = new QVBoxLayout;
 
  layout->addLayout(hlayout);
 
  layout->addWidget(show_again);
 
  setLayout(layout);
 
  setWindowTitle(title);
 
};
 
		
 

	
 
UniqueMessageBox::~UniqueMessageBox(void)  {
 
	
 
	if (show_again->checkState() == Qt::Checked ) {
 
		cerr << "Message won't be shown again\n";
 
		issued_messages << boxtext;
 

	
 
	}
 
  if (show_again->checkState() == Qt::Checked ) {
 
    cerr << "Message won't be shown again\n";
 
    issued_messages << boxtext;
 
  }
 
}
 
int UniqueMessageBox::exec(void)  {
 
	
 
	if (display)
 
		return QDialog::exec();
 
	else {
 
		return 1;
 
	}
 

	
 
  if (display)
 
    return QDialog::exec();
 
  else {
 
    return 1;
 
  }
 
}
 
					   
 

	
 
QStringList UniqueMessageBox::issued_messages;
 
					   
 

	
 
/* finis */
src/UniqueMessage.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _UNIQUEMESSAGE_H_
 
#define _UNIQUEMESSAGE_H_
 

	
 
#include <QDialog>
 
#include <QCheckBox>
 
#include <QStringList>
 
#include <QLabel>
 

	
 
class UniqueMessageBox : public QDialog {
 
	Q_OBJECT
 
	
 
public:
 
	UniqueMessageBox ( /* Icon icon,*/ 
 
			  const QString & title, 
 
			  const QString & text, 
 
			  /* StandardButtons buttons = Ok, */
 
			  QWidget * parent = 0 , Qt::WindowFlags f = Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint );
 
	~UniqueMessageBox();
 
	int exec(void);
 
	
 
private:
 
	static QStringList issued_messages;
 
	bool display;
 
	QCheckBox *show_again;
 
	QPushButton *okButton;
 
	QLabel *label;
 
	QString boxtext;
 
  Q_OBJECT
 

	
 
 public:
 
  UniqueMessageBox ( /* Icon icon,*/ 
 
		    const QString & title, 
 
		    const QString & text, 
 
		    /* StandardButtons buttons = Ok, */
 
		    QWidget * parent = 0 , Qt::WindowFlags f = Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint );
 
  ~UniqueMessageBox();
 
  int exec(void);
 

	
 
 private:
 
  static QStringList issued_messages;
 
  bool display;
 
  QCheckBox *show_again;
 
  QPushButton *okButton;
 
  QLabel *label;
 
  QString boxtext;
 
};
 

	
 
#endif
 

	
 
/* finis */
src/VirtualLeaf.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include <fstream>
 
#include <sstream>
 
#include <cstring>
 
#include <functional> 
 
#include <getopt.h>
 
#include <cerrno>
 
#include "mesh.h"
 
#include "parameter.h"
 
#include "random.h"
 
#include "pi.h"
 
#include "cellitem.h"
 
#include "canvas.h"
 
#include "cell.h"
 
#include "output.h"
 
#include <qwidget.h>
 
#include <q3process.h>
 
#include <qapplication.h>
 
#include <QDesktopWidget>
 
#include <QGraphicsScene>
 
#include <QMessageBox>
 
//Added by qt3to4:
 
#include <QMouseEvent>
 

	
 
#include <unistd.h>
 
#include <q3textstream.h> 
 

	
 
#ifdef HAVE_QWT
 
#include "data_plot.h"
 
#endif
 
#include <QPalette>
 
#include <QBrush>
 
#include <QToolTip>
 
#include "simplugin.h"
 
#include <QPluginLoader>
 
#include <QDir>
 
#include "modelcatalogue.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
extern Parameter par;
 

	
 
MainBase *main_window = 0;
 

	
 
#ifdef XFIGGRAPHICS
 
#define TIMESTEP double Graphics::TimeStep(void)
 
#endif
 

	
 
class PrintNode {
 
public:
 
  void operator() (const Node &n) const 
 
  {
 
    cerr << n.Index() << ": " << n <<  endl;
 
  }
 
};
 

	
 

	
 
class EdgeSource {
 
	
 

	
 
public:
 
  void operator() (Cell &c) {
 
		
 

	
 
    if (c.AtBoundaryP()) {
 
      cerr << "Cell " << c.Index() << " is a source cell.\n";
 
      c.SetSource(0,par.source);
 
    } else {
 
      cerr << "Cell " << c.Index() << " is _not_ a source cell.\n";
 
    }
 
  }
 
};
 

	
 

	
 

	
 
class CellInfo {
 
public:
 
  void operator() (Cell &c,std::ostream &os) const {
 
    os << "Cell " << c.index << " says: " << endl;
 
    os << "c.nodes.size() = " << c.nodes.size() << endl;
 
    for (list<Node *>::iterator i=c.nodes.begin();
 
	 i!=c.nodes.end();
 
	 i++) {
 
      cerr << (*i)->Index() << " ";
 
    }
 
    cerr << endl;
 
  }
 
};
 

	
 
double PINSum(Cell &c) {
 
  return c.Chemical(1) + c.SumTransporters(1);// + c.ReduceCellAndWalls<double>( complex_PijAj );
 
}
 

	
 

	
 
class DrawCell {
 
public:
 
  void operator() (Cell &c,QGraphicsScene &canvas, MainBase &m) const {
 
    if (m.ShowBorderCellsP() || c.Boundary()==Cell::None) {
 
      if (!m.ShowBoundaryOnlyP() && !m.HideCellsP()) {
 
	if (m.ShowToolTipsP()) {
 
	  QString info_string=QString("Cell %1, chemicals: ( %2, %3, %4, %5, %6)\n %7 of PIN1 at walls.\n Area is %8\n PIN sum is %9\n Circumference is %10\n Boundary type is %11").arg(c.Index()).arg(c.Chemical(0)).arg(c.Chemical(1)).arg(c.Chemical(2)).arg(c.Chemical(3)).arg(c.Chemical(4)).arg(c.SumTransporters(1)).arg(c.Area()).arg(PINSum(c)).arg(c.Circumference()).arg(c.BoundaryStr());
 
					
 

	
 
	  info_string += "\n" + c.printednodelist();
 
	  c.Draw(&canvas, info_string);
 
	} else {
 
	  c.Draw(&canvas);
 
	}
 
      }
 
      if (m.ShowCentersP()){
 
	c.DrawCenter(&canvas);
 
      }
 
      if (m.ShowFluxesP()){
 
	c.DrawFluxes(&canvas, par.arrowsize);
 
      }
 
    }
 
  }
 
};
 

	
 
Mesh mesh;
 
bool batch=false;
 

	
 
void MainBase::Plot(int resize_stride) {
 
	
 
void MainBase::Plot(int resize_stride)
 
{
 

	
 
  clear();
 
	
 

	
 
  static int count=0;
 
  if (resize_stride) {
 
    if ( !((++count)%resize_stride) ) {
 
      FitLeafToCanvas();
 
    }
 
  }
 
  mesh.LoopCells(DrawCell(),canvas,*this);
 
	
 

	
 
  if (ShowNodeNumbersP()) 
 
    mesh.LoopNodes( bind2nd (mem_fun_ref ( &Node::DrawIndex), &canvas ) ) ;
 
  if (ShowCellNumbersP()) 
 
    mesh.LoopCells( bind2nd (mem_fun_ref ( &Cell::DrawIndex), &canvas ) ) ;
 
	
 

	
 
  if (ShowCellAxesP()) 
 
    mesh.LoopCells( bind2nd (mem_fun_ref ( &Cell::DrawAxis), &canvas ) );
 
	
 

	
 
  if (ShowCellStrainP()) 
 
    mesh.LoopCells( bind2nd (mem_fun_ref ( &Cell::DrawStrain), &canvas ) );
 
	
 

	
 
  if (ShowWallsP())
 
    mesh.LoopWalls( bind2nd( mem_fun_ref( &Wall::Draw ), &canvas ) );
 
	
 

	
 
  if (ShowApoplastsP()) 
 
    mesh.LoopWalls( bind2nd( mem_fun_ref( &Wall::DrawApoplast ), &canvas ) );
 
 
 

	
 
  if (ShowMeshP()) 
 
    mesh.DrawNodes(&canvas);
 
	
 

	
 
  if (ShowBoundaryOnlyP()) 
 
    mesh.DrawBoundary(&canvas);
 

	
 
  if ( ( batch || MovieFramesP() )) {
 
		
 

	
 
    static int frame = 0;
 
    // frame numbers are sequential for the most frequently written file type.
 
    // for the less frequently written file type they match the other type
 
    if (!(count%par.storage_stride) )  {
 
		
 

	
 
      stringstream fname;
 
      fname << par.datadir << "/leaf.";
 
      fname.fill('0');
 
      fname.width(6);
 
	
 

	
 
      fname << frame << ".jpg";
 
      if (par.storage_stride <= par.xml_storage_stride) {
 
	frame++;
 
      }
 
			
 

	
 
      // Write high-res JPG snapshot every plot step
 
      Save(fname.str().c_str(), "JPEG",1024,768);
 
    }
 
	
 

	
 
    if (!(count%par.xml_storage_stride)) {
 
      stringstream fname;
 
      fname << par.datadir << "/leaf.";
 
      fname.fill('0');
 
      fname.width(6);
 
      fname << frame << ".xml";
 
	
 

	
 
      if (par.xml_storage_stride < par.storage_stride) {
 
	frame++;
 
      }
 
      // Write XML file every ten plot steps
 
      mesh.XMLSave(fname.str().c_str(), XMLSettingsTree());
 
    }
 
  }
 
}
 

	
 

	
 

	
 
INIT {
 
	
 

	
 
  //mesh.SetSimPlugin(plugin);
 
  if (leaffile) { 
 
    xmlNode *settings;
 
    mesh.XMLRead(leaffile, &settings);
 
		
 

	
 
    main_window->XMLReadSettings(settings);
 
    xmlFree(settings);
 
    main_window->UserMessage(QString("Ready. Time is %1").arg(mesh.getTimeHours().c_str()));
 
		
 

	
 
  } else {
 
    mesh.StandardInit();
 
  }
 
}
 

	
 
TIMESTEP {
 
	
 

	
 
  static int i=0;
 
  static int t=0;
 
  static int ncells;
 
	
 

	
 
  if (!batch) {
 
    UserMessage(QString("Time: %1").arg(mesh.getTimeHours().c_str()),0);
 
  }
 
			 
 

	
 
  ncells=mesh.NCells();
 
		
 
				
 

	
 

	
 
  double dh;
 
  		
 

	
 
  if(DynamicCellsP()) {
 
    dh = mesh.DisplaceNodes();
 
			
 

	
 
    // Only allow for node insertion, cell division and cell growth
 
    // if the system has equillibrized
 
    // i.e. cell wall tension equillibrization is much faster
 
    // than biological processes, including division, cell wall yielding
 
    // and cell expansion
 
    mesh.InsertNodes(); // (this amounts to cell wall yielding)
 
			
 

	
 
    if ( (-dh) < par.energy_threshold) {
 
				
 

	
 
      mesh.IncreaseCellCapacityIfNecessary();
 
      mesh.DoCellHouseKeeping();
 
      //mesh.LoopCurrentCells(mem_fun(&plugin->CellHouseKeeping)); // this includes cell division
 
				
 

	
 
      // Reaction diffusion	
 
      mesh.ReactDiffuse(par.rd_dt);
 
				
 
      t++;
 
				
 
      Plot(par.resize_stride);
 
		
 
    }
 
		
 
  } else {
 
			
 
    mesh.ReactDiffuse(par.rd_dt);
 
		
 
    Plot(par.resize_stride);
 
			
 
  }
 
		
 
  i++;
 
  return mesh.getTime();
 
		
 
}
 
		
 
		
 
				
 

	
 

	
 

	
 
/* Called if a cell is clicked */
 
void Cell::OnClick(QMouseEvent *e) {
 
void Cell::OnClick(QMouseEvent *e)
 
{
 
  e = NULL; // use assignment merely to obviate compilation warning
 
}
 
				
 

	
 

	
 
/* Custom message handler - Default appends a newline character to the end of each line. */ 
 
void vlMessageOutput(QtMsgType type, const char *msg)
 
{
 
  switch (type) {
 
  case QtDebugMsg:
 
    //fprintf(stderr, "Debug: %s\n", msg);
 
    cerr << msg << flush;
 
    break;
 
  case QtWarningMsg:
 
    //fprintf(stderr, "Warning: %s\n", msg);
 
    cerr << "Warning: " << msg << flush;
 
    break;
 
  case QtCriticalMsg:
 
    fprintf(stderr, "Critical: %s\n", msg);
 
    cerr << "Critical: " << msg << flush;
 
    break;
 
  case QtFatalMsg:
 
    //fprintf(stderr, "Fatal: %s\n", msg);
 
    cerr << "Fatal: " << msg << flush;
 
    abort();
 
  }
 
}
 
				
 

	
 

	
 
Parameter par;
 
				
 

	
 
int main(int argc,char **argv) {
 
					
 

	
 
  try {
 
						
 

	
 
    int c;
 

	
 
						
 
    char *leaffile=0;
 
    char *modelfile=0;
 
						
 

	
 
    while (1) {
 
							
 

	
 
      //int this_option_optind = optind ? optind : 1;
 
      int option_index = 0;
 
      static struct option long_options[] = {
 
	{"batch", no_argument, NULL, 'b'},
 
	{"leaffile", required_argument, NULL, 'l'},
 
	{"model", required_argument, NULL, 'm'} 
 
      };
 
		
 

	
 
      // short option 'p' creates trouble for non-commandline usage on MacOSX. Option -p changed to -P (capital)
 
      static char *short_options = "blm";
 
      c = getopt_long (argc, argv, "bl:m:",
 
		       long_options, &option_index);
 
      if (c == -1)
 
	break;
 
		
 
		
 

	
 

	
 
      if (c==0) {
 
	printf ("option %s", long_options[option_index].name);
 
	if (optarg)
 
	  printf (" with arg %s", optarg);
 
	printf ("\n");
 
			
 

	
 
	c = short_options[option_index];
 
      }
 
		
 

	
 
      switch (c) {
 
      case 'b':
 
	cerr << "Running in batch mode\n";
 
	batch=true;
 
	break;
 
				
 

	
 
      case 'l':
 
	leaffile=strdup(optarg);
 
	if (!leaffile) {
 
	  throw("Out of memory");
 
	}
 
	printf("Reading leaf state file '%s'\n", leaffile);
 
	break;
 

	
 
      case 'm':
 
	modelfile=strdup(optarg);
 
	if (!modelfile) {
 
	  throw("Out of memory");
 
	}
 
	break;
 
					
 

	
 
      case '?':
 
	break;
 
				
 

	
 
      default:
 
	printf ("?? getopt returned character code 0%o ??\n", c);
 
      }
 
    }
 
	  
 
	  
 

	
 

	
 
    if (optind < argc) {
 
      printf ("non-option ARGV-elements: ");
 
      while (optind < argc)
 
	printf ("%s ", argv[optind++]);
 
      printf ("\n");
 
    }
 

	
 
    bool useGUI = !batch;
 
    qInstallMsgHandler(vlMessageOutput); // custom message handler
 
    QApplication app(argc,argv,useGUI);
 
						
 

	
 

	
 
    
 

	
 
    QPalette tooltippalette = QToolTip::palette();
 
    QColor transparentcolor = QColor(tooltippalette.brush(QPalette::Window).color());
 

	
 
    tooltippalette.setBrush (QPalette::Window, QBrush (transparentcolor) );
 
    QToolTip::setPalette( tooltippalette );
 

	
 
    QGraphicsScene canvas(0,0,8000,6000);
 

	
 
	  
 

	
 
    if (useGUI) {
 
      main_window=new Main(canvas, mesh);
 
      if ( QApplication::desktop()->width() > ((Main *)main_window)->width() + 10
 
	   && QApplication::desktop()->height() > ((Main *)main_window)->height() +30 ) {
 

	
 
	((Main *)main_window)->show();
 
	((Main *)main_window)->resize( ((Main *)main_window)->sizeHint());
 
      } else {
 
        ((Main *)main_window)->showMaximized();
 
      }
 
    } else {
 
      main_window=new MainBase(canvas, mesh);
 

	
 
    }
 

	
 
    
 
	  
 
    canvas.setSceneRect(QRectF());
 
    if (!batch) {
 
      QObject::connect( qApp, SIGNAL(lastWindowClosed()), qApp, SLOT(quit()) );
 
    }
 

	
 
    // Install model or read catalogue of models
 
    ModelCatalogue model_catalogue(&mesh, useGUI?(Main *)main_window:0,modelfile);
 
    if (useGUI)
 
      model_catalogue.PopulateModelMenu();
 
    model_catalogue.InstallFirstModel();
 
    
 

	
 
    if (leaffile) 
 
      main_window->Init(leaffile);
 
	  
 

	
 
    Cell::SetMagnification(1);
 
    Cell::setOffset(0,0);
 
						
 

	
 
    main_window->FitLeafToCanvas();
 
							
 

	
 
    main_window->Plot();
 

	
 
    if (batch) {
 
      double t=0.;
 
      do {
 
	t = main_window->TimeStep();
 
      } while (t < par.maxt);
 
							
 
    } else
 
      return app.exec();
 
	  
 
						
 

	
 
  } catch (const char *message) {
 
    if (batch) { 
 
      cerr << "Exception caught:" << endl;
 
      cerr << message << endl;
 
      abort();
 
    } else {
 
      QString qmess=QString("Exception caught: %1").arg(message);
 
      QMessageBox::critical(0, "Critical Error", qmess);
 
      abort();
 
    }
 
  } catch (ios_base::failure) {
 
    stringstream error_message;
 
    error_message << "I/O failure: " << strerror(errno);
 
    if (batch) {
 
      cerr << error_message.str() <<endl;
 
      abort();
 
    } else {
 
      QString qmess(error_message.str().c_str());
 
      QMessageBox::critical(0, "I/O Error", qmess );
 
      abort();
 
    }
 
  }
 
}
 

	
 
/* finis */
src/apoplastitem.cpp
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#include <string>
 
#include <QGraphicsScene>
 
#include "canvas.h"
 
#include "parameter.h"
 
#include "node.h"
 
#include "apoplastitem.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
ApoplastItem::ApoplastItem( Wall *w, QGraphicsScene *canvas )
 
: QGraphicsLineItem( 0, canvas ), SimItemBase( w, canvas){
 
		
 
	setColor();
 
	
 
	// line with "PIN1"is a bit inside the cell wall
 
	Vector edgevec = (*(w->N2())) - (*(w->N1()));
 
	Vector perp = edgevec.Normalised().Perp2D();
 
	
 
	Vector offs = Cell::Offset();
 
	double factor = Cell::Factor();
 
	
 
	Vector from = ( offs + *(w->N1()) ) * factor;
 
	Vector to = ( offs + *(w->N2()) ) *factor;
 
	
 
	
 
	setLine(( from.x ),
 
			( from.y ),
 
			( to.x ),
 
			( to.y ) );
 
	setZValue(12);
 
  : QGraphicsLineItem( 0, canvas ), SimItemBase( w, canvas){
 

	
 
  setColor();
 

	
 
  // line with "PIN1"is a bit inside the cell wall
 
  Vector edgevec = (*(w->N2())) - (*(w->N1()));
 
  Vector perp = edgevec.Normalised().Perp2D();
 

	
 
  Vector offs = Cell::Offset();
 
  double factor = Cell::Factor();
 

	
 
  Vector from = ( offs + *(w->N1()) ) * factor;
 
  Vector to = ( offs + *(w->N2()) ) *factor;
 

	
 

	
 
  setLine(( from.x ),
 
	  ( from.y ),
 
	  ( to.x ),
 
	  ( to.y ) );
 
  setZValue(12);
 
}
 

	
 

	
 
void ApoplastItem::setColor(void) {
 
	
 
	QColor diffcolor;
 
	static const QColor purple("Purple");
 
	static const QColor blue("blue");
 
	
 
	Wall *w=&getWall();
 
	double val = w->getApoplast(2);
 

	
 
  QColor diffcolor;
 
  static const QColor purple("Purple");
 
  static const QColor blue("blue");
 

	
 
	diffcolor.setRgb( 0,0,(int)( ( val / (1 + val) )*255.));
 
	setPen (QPen(diffcolor, 20) );
 
  Wall *w=&getWall();
 
  double val = w->getApoplast(2);
 

	
 
  diffcolor.setRgb( 0,0,(int)( ( val / (1 + val) )*255.));
 
  setPen (QPen(diffcolor, 20) );
 
}
 

	
 
void ApoplastItem::OnClick(QMouseEvent *e) {
 
  e = NULL; // merely to obviate compilation warnings
 
}
 

	
 
/* finis*/
src/apoplastitem.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#ifndef _APOPLASTITEM_H_
 
#define _APOPLASTITEM_H_
 

	
 
#include <QGraphicsScene>
 
#include <QGraphicsLineItem>
 
#include <QPainter>
 
#include <qpainter.h>
 
#include <QMouseEvent>
 
#include "simitembase.h"
 
#include "wall.h"
 

	
 
//! Shows transporter concentrations at one side of the wall
 

	
 
class ApoplastItem : public QGraphicsLineItem, public SimItemBase
 
{
 
public:
 
	ApoplastItem( Wall *n, QGraphicsScene *canvas );
 
	virtual ~ApoplastItem() {}
 
	Wall &getWall(void) const { return *class_cast<Wall*>(obj); }
 
	void OnClick(QMouseEvent *e);  
 
	void setColor(void);
 
private:
 
	int wn;
 
 public:
 
  ApoplastItem( Wall *n, QGraphicsScene *canvas );
 
  virtual ~ApoplastItem() {}
 
  Wall &getWall(void) const { return *class_cast<Wall*>(obj); }
 
  void OnClick(QMouseEvent *e);  
 
  void setColor(void);
 
 private:
 
  int wn;
 
};
 

	
 
#endif
 

	
 
/* finis*/
src/build_models/auxingrowthplugin.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <QObject>
 
#include <QtGui>
 
#include "../simplugin.h"
 

	
 
#include "parameter.h"
 

	
 
#include "wallbase.h"
 
#include "cellbase.h"
 
#include "auxingrowthplugin.h"
 

	
 
#include "far_mem_5.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
bool batch = false;
 

	
 

	
 
// To be executed after cell division
 
void AuxinGrowthPlugin::OnDivide(ParentInfo *parent_info, CellBase *daughter1, CellBase *daughter2) {
 
void AuxinGrowthPlugin::OnDivide(ParentInfo *parent_info, CellBase *daughter1, CellBase *daughter2)
 
{
 
  parent_info = NULL; // merely to obviate compile time error
 

	
 
	// Auxin distributes between parent and daughter according to area
 
	double area1 = daughter1->Area(), area2 = daughter2->Area();
 
	double tot_area = area1 + area2;
 
  // Auxin distributes between parent and daughter according to area
 
  double area1 = daughter1->Area(), area2 = daughter2->Area();
 
  double tot_area = area1 + area2;
 
	
 
	daughter1->SetChemical(0,daughter1->Chemical(0)*(area1/tot_area));
 
	daughter2->SetChemical(0,daughter2->Chemical(0)*(area2/tot_area));
 
  daughter1->SetChemical(0,daughter1->Chemical(0)*(area1/tot_area));
 
  daughter2->SetChemical(0,daughter2->Chemical(0)*(area2/tot_area));
 
	
 
	// After divisions, parent and daughter cells get a standard stock of PINs.
 
	daughter1->SetChemical(1, par->initval[1]);
 
	daughter2->SetChemical(1, par->initval[1]);
 
  // After divisions, parent and daughter cells get a standard stock of PINs.
 
  daughter1->SetChemical(1, par->initval[1]);
 
  daughter2->SetChemical(1, par->initval[1]);
 
	
 
	
 
	// Reset transporter values of parent and daughter
 
	QList<WallBase *> walls;
 
	foreach(WallBase *w, walls) { 
 
		w->setTransporter(daughter1, 1, 0.);
 
	}
 
	
 
  // Reset transporter values of parent and daughter
 
  QList<WallBase *> walls;
 
  foreach(WallBase *w, walls) { 
 
    w->setTransporter(daughter1, 1, 0.);
 
  }
 
}
 

	
 
void AuxinGrowthPlugin::SetCellColor(CellBase *c, QColor *color) { 
 
void AuxinGrowthPlugin::SetCellColor(CellBase *c, QColor *color)
 
{ 
 

	
 
	// Red: PIN1
 
	// Green: Auxin
 
	if (c->CellType()==1) color->setNamedColor("Blue"); 
 
	else color->setRgb(c->Chemical(1)/(1+c->Chemical(1)) * 255.,(c->Chemical(0)/(1+c->Chemical(0)) * 255.),/* (chem[2]/(1+chem[2]) *255.) */ 0);
 
	
 
  // Red: PIN1
 
  // Green: Auxin
 
  if (c->CellType()==1)
 
    color->setNamedColor("Blue"); 
 
  else 
 
    color->setRgb(c->Chemical(1)/(1+c->Chemical(1)) * 255.,(c->Chemical(0)/(1+c->Chemical(0)) * 255.), 0);
 
}
 

	
 

	
 

	
 
void AuxinGrowthPlugin::CellHouseKeeping(CellBase *c) {
 

	
 
	if (c->Boundary()==CellBase::None) {
 
		if (c->Area() > par->rel_cell_div_threshold * c->BaseArea() ) {
 
			c->SetChemical(0,0);
 
			c->Divide();
 
        }		
 
		if (c->Chemical(0)>0.6) {
 
			c->SetCellType(1);
 
		} 
 
		// expand according to auxin concentration
 
   		c->EnlargeTargetArea(par->auxin_dependent_growth?(c->Chemical(0)/(1.+c->Chemical(0)))*par->cell_expansion_rate:par->cell_expansion_rate);
 
	}  
 
	
 

	
 
void AuxinGrowthPlugin::CellHouseKeeping(CellBase *c)
 
{
 
  if (c->Boundary()==CellBase::None) {
 
    if (c->Area() > par->rel_cell_div_threshold * c->BaseArea() ) {
 
      c->SetChemical(0,0);
 
      c->Divide();
 
    }		
 
    if (c->Chemical(0)>0.6) {
 
      c->SetCellType(1);
 
    } 
 
    // expand according to auxin concentration
 
    c->EnlargeTargetArea(par->auxin_dependent_growth?(c->Chemical(0)/(1.+c->Chemical(0)))*par->cell_expansion_rate:par->cell_expansion_rate);
 
  }  
 
}
 

	
 
void AuxinGrowthPlugin::CelltoCellTransport(Wall *w, double *dchem_c1, double *dchem_c2) {
 
void AuxinGrowthPlugin::CelltoCellTransport(Wall *w, double *dchem_c1, double *dchem_c2)
 
{
 

	
 
	// leaf edge is const source of auxin
 
    // (Neumann boundary condition: we specify the influx)
 
    if (w->C2()->BoundaryPolP()) {
 
		if (w->AuxinSource()) {
 
			double aux_flux = par->leaf_tip_source * w->Length();
 
			dchem_c1[0]+= aux_flux;
 
			return;
 
		} else {
 
			return;
 
		}
 
	}
 
  // leaf edge is const source of auxin
 
  // (Neumann boundary condition: we specify the influx)
 
  if (w->C2()->BoundaryPolP()) {
 
    if (w->AuxinSource()) {
 
      double aux_flux = par->leaf_tip_source * w->Length();
 
      dchem_c1[0]+= aux_flux;
 
      return;
 
    } else {
 
      return;
 
    }
 
  }
 
	
 
	
 
	if (w->C1()->BoundaryPolP()) {
 
  if (w->C1()->BoundaryPolP()) {
 
		
 
		if (w->AuxinSource()) {
 
			double aux_flux = par->leaf_tip_source * w->Length();
 
			dchem_c2[0] += aux_flux;
 
			return;
 
		} else {
 
    if (w->AuxinSource()) {
 
      double aux_flux = par->leaf_tip_source * w->Length();
 
      dchem_c2[0] += aux_flux;
 
      return;
 
    } else {
 
			
 
			if (w->AuxinSink()) {
 
      if (w->AuxinSink()) {
 
				
 
				// efflux into Shoot Apical meristem
 
				// we assume all PINs are directed towards shoot apical meristem
 
				dchem_c2[0] -= par->sam_efflux * w->C2()->Chemical(0) / (par->ka + w->C2()->Chemical(0));
 
	// efflux into Shoot Apical meristem
 
	// we assume all PINs are directed towards shoot apical meristem
 
	dchem_c2[0] -= par->sam_efflux * w->C2()->Chemical(0) / (par->ka + w->C2()->Chemical(0));
 
				
 
				return;
 
			} else 
 
				return;
 
		}
 
	return;
 
      } else 
 
	return;
 
    }
 
  }
 
	
 
    
 
	// Passive fluxes (Fick's law)
 
    // only auxin flux now
 
    // flux depends on edge length and concentration difference
 
    int c=0;
 
    double phi = w->Length() * ( par->D[c] ) * ( w->C2()->Chemical(c) - w->C1()->Chemical(c) );
 
    dchem_c1[c] += phi; 
 
    dchem_c2[c] -= phi;
 
  // Passive fluxes (Fick's law)
 
  // only auxin flux now
 
  // flux depends on edge length and concentration difference
 
  int c=0;
 
  double phi = w->Length() * ( par->D[c] ) * ( w->C2()->Chemical(c) - w->C1()->Chemical(c) );
 
  dchem_c1[c] += phi; 
 
  dchem_c2[c] -= phi;
 
	
 
    // Active fluxes (PIN1 mediated transport)
 
  // Active fluxes (PIN1 mediated transport)
 
	
 
    // (Transporters measured in moles, here)
 
    // efflux from cell 1 to cell 2
 
    double trans12 = ( par->transport * w->Transporters1(1) * w->C1()->Chemical(0) / (par->ka + w->C1()->Chemical(0)) );
 
  // (Transporters measured in moles, here)
 
  // efflux from cell 1 to cell 2
 
  double trans12 = ( par->transport * w->Transporters1(1) * w->C1()->Chemical(0) / (par->ka + w->C1()->Chemical(0)) );
 
	
 
    // efflux from cell 2 to cell 1
 
    double trans21 = ( par->transport * w->Transporters2(1) * w->C2()->Chemical(0) / (par->ka + w->C2()->Chemical(0)) );
 
  // efflux from cell 2 to cell 1
 
  double trans21 = ( par->transport * w->Transporters2(1) * w->C2()->Chemical(0) / (par->ka + w->C2()->Chemical(0)) );
 
    
 
    dchem_c1[0] += trans21 - trans12;
 
    dchem_c2[0] += trans12 - trans21;
 
  dchem_c1[0] += trans21 - trans12;
 
  dchem_c2[0] += trans12 - trans21;
 
	
 
}
 

	
 
void AuxinGrowthPlugin::WallDynamics(Wall *w, double *dw1, double *dw2) {
 

	
 
	
 
	
 
    // Cells polarize available PIN1 to Shoot Apical Meristem
 
    if (w->C2()->BoundaryPolP()) {
 
		if (w->AuxinSink()) {
 
void AuxinGrowthPlugin::WallDynamics(Wall *w, double *dw1, double *dw2)
 
{
 
  // Cells polarize available PIN1 to Shoot Apical Meristem
 
  if (w->C2()->BoundaryPolP()) {
 
    if (w->AuxinSink()) {
 
			
 
			dw1[0] = 0.; dw2[0] = 0.;
 
      dw1[0] = 0.; dw2[0] = 0.;
 
            
 
			// assume high auxin concentration in SAM, to convince PIN1 to polarize to it
 
			// exocytosis regulated0
 
			double nb_auxin = par->sam_auxin;
 
			double receptor_level = nb_auxin * par->r / (par->kr + nb_auxin);
 
      // assume high auxin concentration in SAM, to convince PIN1 to polarize to it
 
      // exocytosis regulated0
 
      double nb_auxin = par->sam_auxin;
 
      double receptor_level = nb_auxin * par->r / (par->kr + nb_auxin);
 
			
 
			dw1[1] = par->k1 * w->C1()->Chemical(1) * receptor_level /( par->km + w->C1()->Chemical(1) ) - par->k2 * w->Transporters1(1);
 
      dw1[1] = par->k1 * w->C1()->Chemical(1) * receptor_level /( par->km + w->C1()->Chemical(1) ) - par->k2 * w->Transporters1(1);
 
			
 
			dw2[1] = 0.;
 
			return;
 
      dw2[1] = 0.;
 
      return;
 
			
 
		} else {
 
			dw1[0]=dw2[0]=dw1[1]=dw2[1];
 
			return;
 
		}
 
    } else {
 
      dw1[0]=dw2[0]=dw1[1]=dw2[1];
 
      return;
 
    }
 
  }
 
    
 
    if (w->C1()->BoundaryPolP()) {
 
		if (w->AuxinSink())  {
 
  if (w->C1()->BoundaryPolP()) {
 
    if (w->AuxinSink())  {
 
			
 
			dw1[0] = 0.; dw2[0] = 0.;
 
      dw1[0] = 0.; dw2[0] = 0.;
 
			
 
			// assume high auxin concentration in SAM, to convince PIN1 to polarize to it
 
			// exocytosis regulated
 
			double nb_auxin = par->sam_auxin;
 
			double receptor_level = nb_auxin * par->r / (par->kr + nb_auxin);
 
			dw2[1] = par->k1 * w->C2()->Chemical(1) * receptor_level /( par->km + w->C2()->Chemical(1) ) - par->k2 * w->Transporters2(1);
 
      // assume high auxin concentration in SAM, to convince PIN1 to polarize to it
 
      // exocytosis regulated
 
      double nb_auxin = par->sam_auxin;
 
      double receptor_level = nb_auxin * par->r / (par->kr + nb_auxin);
 
      dw2[1] = par->k1 * w->C2()->Chemical(1) * receptor_level /( par->km + w->C2()->Chemical(1) ) - par->k2 * w->Transporters2(1);
 
			
 
			dw1[1] = 0.;
 
			return;
 
      dw1[1] = 0.;
 
      return;
 
			
 
		}  else {
 
			dw1[0]=dw2[0]=dw1[1]=dw2[1];
 
			return;
 
		}
 
    }  else {
 
      dw1[0]=dw2[0]=dw1[1]=dw2[1];
 
      return;
 
    }
 
  }
 
    
 
    
 
    
 
    // PIN1 localization at wall 1
 
    // Note: chemical 0 is Auxin (intracellular storage only)
 
    // Chemical 1 is PIN1 (walls and intracellular storage)
 
    //! \f$ \frac{d Pij/dt}{dt} = k_1 A_j \frac{P_i}{L_ij} - k_2 P_{ij} \f$
 
    // Note that Pij is measured in term of concentration (mol/L)
 
    // Pi in terms of quantity (mol)
 
  // PIN1 localization at wall 1
 
  // Note: chemical 0 is Auxin (intracellular storage only)
 
  // Chemical 1 is PIN1 (walls and intracellular storage)
 
  //! \f$ \frac{d Pij/dt}{dt} = k_1 A_j \frac{P_i}{L_ij} - k_2 P_{ij} \f$
 
  // Note that Pij is measured in term of concentration (mol/L)
 
  // Pi in terms of quantity (mol)
 
	
 
    double dPijdt1=0., dPijdt2=0.;
 
  double dPijdt1=0., dPijdt2=0.;
 
    
 
    // normal cell
 
    double  auxin2 = w->C2()->Chemical(0);
 
    double receptor_level1 = auxin2 * par->r / (par->kr + auxin2);
 
  // normal cell
 
  double  auxin2 = w->C2()->Chemical(0);
 
  double receptor_level1 = auxin2 * par->r / (par->kr + auxin2);
 
    
 
    dPijdt1 = 
 
	// exocytosis regulated
 
  dPijdt1 = 
 
    // exocytosis regulated
 
    par->k1 * w->C1()->Chemical(1) * receptor_level1 / ( par->km + w->C1()->Chemical(1) ) - par->k2 * w->Transporters1(1);
 
	
 
    double  auxin1 = w->C1()->Chemical(0);
 
    double receptor_level2 = auxin1 * par->r / (par->kr + auxin1);
 
  double  auxin1 = w->C1()->Chemical(0);
 
  double receptor_level2 = auxin1 * par->r / (par->kr + auxin1);
 
    
 
    // normal cell
 
    dPijdt2 = 
 
  // normal cell
 
  dPijdt2 = 
 
	
 
	// exocytosis regulated
 
	par->k1 * w->C2()->Chemical(1) * receptor_level2 / ( par->km + w->C2()->Chemical(1) ) - par->k2 * w->Transporters2(1);
 
    // exocytosis regulated
 
    par->k1 * w->C2()->Chemical(1) * receptor_level2 / ( par->km + w->C2()->Chemical(1) ) - par->k2 * w->Transporters2(1);
 
    
 
    /* PIN1 of neighboring vascular cell inhibits PIN1 endocytosis */
 
  /* PIN1 of neighboring vascular cell inhibits PIN1 endocytosis */
 
    
 
    dw1[0] = 0.; dw2[0] = 0.;
 
    dw1[1] = dPijdt1;
 
    dw2[1] = dPijdt2;
 
  dw1[0] = 0.; dw2[0] = 0.;
 
  dw1[1] = dPijdt1;
 
  dw2[1] = dPijdt2;
 
}
 

	
 
double AuxinGrowthPlugin::complex_PijAj(CellBase *here, CellBase *nb, Wall *w) { 
 
	
 
	// gives the amount of complex "auxinreceptor-Pin1"  at the wall (at QSS) 
 
	//return here.Chemical(1) * nb.Chemical(0) / ( par->km + here.Chemical(1));
 
	
 
	double nb_aux = (nb->BoundaryPolP() && w->AuxinSink()) ? par->sam_auxin : nb->Chemical(0);
 
	double receptor_level = nb_aux * par->r / (par->kr + nb_aux);
 
	
 
	return here->Chemical(1) * receptor_level / ( par->km + here->Chemical(1));
 
	
 
}
 

	
 
void AuxinGrowthPlugin::CellDynamics(CellBase *c, double *dchem) {
 
	// Note: Pi and Pij measured in numbers of molecules, not concentrations		
 
		double dPidt = 0.;
 
		
 
		double sum_Pij = c->SumTransporters( 1 );
 
		
 
		// exocytosis regulated:
 
double AuxinGrowthPlugin::complex_PijAj(CellBase *here, CellBase *nb, Wall *w)
 
{ 
 
  // gives the amount of complex "auxinreceptor-Pin1"  at the wall (at QSS) 
 
  //return here.Chemical(1) * nb.Chemical(0) / ( par->km + here.Chemical(1));
 
	
 
	dPidt = -par->k1 * c->ReduceCellAndWalls<double>( far_3_arg_mem_fun( *this, &AuxinGrowthPlugin::complex_PijAj ) ) + par->k2 * sum_Pij;
 
	
 
	// production of PIN depends on auxin concentration
 
	dPidt +=  (c->AtBoundaryP()?par->pin_prod_in_epidermis:par->pin_prod) * c->Chemical(0) - c->Chemical(1) * par->pin_breakdown;
 
  double nb_aux = (nb->BoundaryPolP() && w->AuxinSink()) ? par->sam_auxin : nb->Chemical(0);
 
  double receptor_level = nb_aux * par->r / (par->kr + nb_aux);
 
	
 
	// no PIN production in SAM
 
	if (c->Boundary() == CellBase::SAM) {
 
			dchem[1]=0.;
 
		dchem[0]= - par->sam_auxin_breakdown * c->Chemical(0);
 
	} else {
 
		
 
		dchem[1] = dPidt;
 
		
 
		
 
		// source of auxin
 
		dchem[0] = par->aux_cons - par->aux_breakdown * c->Chemical(0);
 
		
 
	}
 
	
 
	
 
  return here->Chemical(1) * receptor_level / ( par->km + here->Chemical(1));
 
	
 
}
 

	
 

	
 
void AuxinGrowthPlugin::CellDynamics(CellBase *c, double *dchem)
 
{
 
  // Note: Pi and Pij measured in numbers of molecules, not concentrations		
 
  double dPidt = 0.;
 
		
 
  double sum_Pij = c->SumTransporters( 1 );
 
		
 
  // exocytosis regulated:
 
	
 
  dPidt = -par->k1 * c->ReduceCellAndWalls<double>( far_3_arg_mem_fun( *this, &AuxinGrowthPlugin::complex_PijAj ) ) + par->k2 * sum_Pij;
 
	
 
  // production of PIN depends on auxin concentration
 
  dPidt +=  (c->AtBoundaryP()?par->pin_prod_in_epidermis:par->pin_prod) * c->Chemical(0) - c->Chemical(1) * par->pin_breakdown;
 
	
 
  // no PIN production in SAM
 
  if (c->Boundary() == CellBase::SAM) {
 
    dchem[1]=0.;
 
    dchem[0]= - par->sam_auxin_breakdown * c->Chemical(0);
 
  } else {
 
		
 
    dchem[1] = dPidt;
 
		
 
    // source of auxin
 
    dchem[0] = par->aux_cons - par->aux_breakdown * c->Chemical(0);
 
  }
 
}
 

	
 
Q_EXPORT_PLUGIN2(auxingrowthplugin, AuxinGrowthPlugin)
 

	
 
/* finis */
src/build_models/auxingrowthplugin.h
Show inline comments
 
/*
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#ifndef _AUXINGROWTHPLUGIN_H_
 
#define _AUXINGROWTHPLUGIN_H_
 

	
 
#include <QObject>
 
#include <QtGui>
 
#include <QString>
 
#include "../simplugin.h"
 

	
 

	
 
class AuxinGrowthPlugin : public QObject, SimPluginInterface {
 
	Q_OBJECT
 
	Q_INTERFACES(SimPluginInterface);
 
  Q_OBJECT
 
  Q_INTERFACES(SimPluginInterface);
 

	
 
public:
 
	virtual QString ModelID(void) { return QString( "Auxin accumulation and growth" ); }
 
 public:
 
  virtual QString ModelID(void) { return QString( "Auxin accumulation and growth" ); }
 
	
 
	// Executed after the cellular mechanics steps have equillibrized
 
	virtual void CellHouseKeeping (CellBase *c);
 
	// Differential equations describing transport of chemicals from cell to cell
 
	virtual void CelltoCellTransport(Wall *w, double *dchem_c1, double *dchem_c2);
 
  // Executed after the cellular mechanics steps have equillibrized
 
  virtual void CellHouseKeeping (CellBase *c);
 
  // Differential equations describing transport of chemicals from cell to cell
 
  virtual void CelltoCellTransport(Wall *w, double *dchem_c1, double *dchem_c2);
 
    
 
	// Differential equations describing chemical reactions taking place at or near the cell walls
 
	// (e.g. PIN accumulation)
 
	virtual void WallDynamics(Wall *w, double *dw1, double *dw2);
 
  // Differential equations describing chemical reactions taking place at or near the cell walls
 
  // (e.g. PIN accumulation)
 
  virtual void WallDynamics(Wall *w, double *dw1, double *dw2);
 
	
 
	// Differential equations describing chemical reactions inside the cells
 
	virtual void CellDynamics(CellBase *c, double *dchem);
 
  // Differential equations describing chemical reactions inside the cells
 
  virtual void CellDynamics(CellBase *c, double *dchem);
 
	
 
	// to be executed after a cell division
 
	virtual void OnDivide(ParentInfo *parent_info, CellBase *daughter1, CellBase *daughter2);
 
  // to be executed after a cell division
 
  virtual void OnDivide(ParentInfo *parent_info, CellBase *daughter1, CellBase *daughter2);
 
	
 
	// to be executed for coloring a cell
 
	virtual void SetCellColor(CellBase *c, QColor *color);	
 
	// return number of chemicals
 
	virtual int NChem(void) { return 2; }
 
  // to be executed for coloring a cell
 
  virtual void SetCellColor(CellBase *c, QColor *color);	
 
  // return number of chemicals
 
  virtual int NChem(void) { return 2; }
 
	
 
private:
 
	double complex_PijAj(CellBase *here, CellBase *nb, Wall *w);
 
 private:
 
  double complex_PijAj(CellBase *here, CellBase *nb, Wall *w);
 
};
 

	
 
#endif
 

	
 
/* finis */
src/build_models/meinhardtplugin.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <QObject>
 
#include <QtGui>
 
#include "../simplugin.h"
 

	
 
#include "parameter.h"
 
#include "warning.h"
 
#include "wallbase.h"
 
#include "cellbase.h"
 
#include "meinhardtplugin.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
bool batch = false;
 

	
 
// To be executed after cell division
 
void MeinhardtPlugin::OnDivide(ParentInfo *parent_info, CellBase *daughter1, CellBase *daughter2) {
 
  parent_info = NULL;
 
  daughter1 = daughter2 = NULL;
 
}
 

	
 
void MeinhardtPlugin::SetCellColor(CellBase *c, QColor *color) { 
 

	
 
	if (fpclassify(c->Chemical(0))==FP_NAN) {
 
		// somehow the function isnan doesn't work properly on my system... SuSE Linux
 
		// 10.0 64-bits (isnan seems not be implemented using fpclassify).
 
		MyWarning::warning("Whoops! Numerical instability!!");
 
		color->setNamedColor("red");
 
	} else {
 
		double range_min = 0.;//, range_max = 1.;
 
		if (c->Chemical(0)<range_min) {
 
			MyWarning::warning("Whoops! Numerical instability!!");
 
			color->setNamedColor("blue");
 
		} else {
 
			color->setRgb(c->Chemical(1)/(1+c->Chemical(1)) * 255.,(c->Chemical(0)/(1+c->Chemical(0)) * 255.),(c->Chemical(3)/(1+c->Chemical(3)) *255.) );
 
		}
 
		
 
	}
 
  if (fpclassify(c->Chemical(0))==FP_NAN) {
 
    // somehow the function isnan doesn't work properly on my system... SuSE Linux
 
    // 10.0 64-bits (isnan seems not be implemented using fpclassify).
 
    MyWarning::warning("Whoops! Numerical instability!!");
 
    color->setNamedColor("red");
 
  } else {
 
    double range_min = 0.;//, range_max = 1.;
 
    if (c->Chemical(0)<range_min) {
 
      MyWarning::warning("Whoops! Numerical instability!!");
 
      color->setNamedColor("blue");
 
    } else {
 
      color->setRgb(c->Chemical(1)/(1+c->Chemical(1)) * 255.,(c->Chemical(0)/(1+c->Chemical(0)) * 255.),(c->Chemical(3)/(1+c->Chemical(3)) *255.) );
 
    }
 
  }
 
}
 

	
 

	
 

	
 
void MeinhardtPlugin::CellHouseKeeping(CellBase *c) {
 
	
 
	if (c->Area() > par->rel_cell_div_threshold * c->BaseArea() ) {
 
		c->Divide();
 
	}
 
  if (c->Area() > par->rel_cell_div_threshold * c->BaseArea() ) {
 
    c->Divide();
 
  }
 
	
 
    // cell expansion is inhibited by substrate (chem 3)
 
	if (!par->constituous_expansion_limit || c->NCells()<par->constituous_expansion_limit) {
 
		c->EnlargeTargetArea(par->cell_expansion_rate );
 
	} else {
 
		if (c->Chemical(0)<0.5) {
 
			double tmp;
 
			c->EnlargeTargetArea((tmp=(1.-par->vessel_inh_level*c->Chemical(3))*par->cell_expansion_rate /* + c->Chemical(4)*/)<0?0:tmp); 
 
		} else {
 
			c->EnlargeTargetArea(par->vessel_expansion_rate);
 
		}
 
	} 
 
    
 
  // cell expansion is inhibited by substrate (chem 3)
 
  if (!par->constituous_expansion_limit || c->NCells()<par->constituous_expansion_limit) {
 
    c->EnlargeTargetArea(par->cell_expansion_rate );
 
  } else {
 
    if (c->Chemical(0)<0.5) {
 
      double tmp;
 
      c->EnlargeTargetArea((tmp=(1.-par->vessel_inh_level*c->Chemical(3))*par->cell_expansion_rate /* + c->Chemical(4)*/)<0?0:tmp); 
 
    } else {
 
      c->EnlargeTargetArea(par->vessel_expansion_rate);
 
    }
 
  } 
 
}
 

	
 
void MeinhardtPlugin::CelltoCellTransport(Wall *w, double *dchem_c1, double *dchem_c2) {
 
	
 
	// No flux boundaries for all chemicals, except activator: boundary is sink
 
  // No flux boundaries for all chemicals, except activator: boundary is sink
 
  if (w->C1()->BoundaryPolP() || w->C2()->BoundaryPolP()) {
 
		
 
		if (w->C1()->BoundaryPolP()) {
 
			dchem_c2[1] -=  w->Length() * ( par->D[1] ) * ( w->C2()->Chemical(1) );
 
			} else {
 
			dchem_c1[1] -=  w->Length() * ( par->D[1] ) * ( w->C1()->Chemical(1) );
 
			} 
 
		return;
 
		}
 
    if (w->C1()->BoundaryPolP()) {
 
      dchem_c2[1] -=  w->Length() * ( par->D[1] ) * ( w->C2()->Chemical(1) );
 
    } else {
 
      dchem_c1[1] -=  w->Length() * ( par->D[1] ) * ( w->C1()->Chemical(1) );
 
    } 
 
    return;
 
  }
 
	
 

	
 
    // Passive fluxes (Fick's law)
 
    for (int c=0;c<NChem();c++) {
 
		double phi = w->Length() * ( par->D[c] ) * ( w->C2()->Chemical(c) - w->C1()->Chemical(c) );
 
		dchem_c1[c] += phi; 
 
		dchem_c2[c] -= phi;
 
	}
 
   
 

	
 
  // Passive fluxes (Fick's law)
 
  for (int c=0;c<NChem();c++) {
 
    double phi = w->Length() * ( par->D[c] ) * ( w->C2()->Chemical(c) - w->C1()->Chemical(c) );
 
    dchem_c1[c] += phi; 
 
    dchem_c2[c] -= phi;
 
  }
 
}
 

	
 
void MeinhardtPlugin::WallDynamics(Wall *w, double *dw1, double *dw2) {
 
  w = NULL;
 
	for (int c = 0;c<NChem();c++) {
 
		dw1[c] = 0.; dw2[c] = 0.;
 
    }
 
  for (int c = 0;c<NChem();c++) {
 
    dw1[c] = 0.; dw2[c] = 0.;
 
  }
 
}
 

	
 
void MeinhardtPlugin::CellDynamics(CellBase *c, double *dchem) {
 

	
 
	double Y = c->Chemical(0);
 
	double A = c->Chemical(1);
 
	double H = c->Chemical(2);
 
	double S = c->Chemical(3);
 

	
 
  double Y = c->Chemical(0);
 
  double A = c->Chemical(1);
 
  double H = c->Chemical(2);
 
  double S = c->Chemical(3);
 
	
 
	
 
    dchem[0] = ( par->d * A - par->e * Y + Y*Y/(1 + par->f * Y*Y ) );
 
	dchem[1] = ( par->c * A*A*S/H - par->mu * A + par->rho0*Y );
 
	dchem[2] = ( par->c * A*A*S - par->nu*H + par->rho1*Y );
 
	dchem[3] = ( par->c0 - par->gamma*S - par->eps * Y * S );
 
  dchem[0] = ( par->d * A - par->e * Y + Y*Y/(1 + par->f * Y*Y ) );
 
  dchem[1] = ( par->c * A*A*S/H - par->mu * A + par->rho0*Y );
 
  dchem[2] = ( par->c * A*A*S - par->nu*H + par->rho1*Y );
 
  dchem[3] = ( par->c0 - par->gamma*S - par->eps * Y * S );
 
}
 

	
 

	
 
Q_EXPORT_PLUGIN2(meinhardtplugin, MeinhardtPlugin)
 

	
 
/* finis */
src/build_models/meinhardtplugin.h
Show inline comments
 
/*
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#ifndef _MEINHARDTPLUGIN_H_
 
#define _MEINHARDTPLUGIN_H_
 

	
 
#include <QObject>
 
#include <QtGui>
 
#include <QString>
 
#include "../simplugin.h"
 

	
 

	
 
class MeinhardtPlugin : public QObject, SimPluginInterface {
 
	Q_OBJECT
 
	Q_INTERFACES(SimPluginInterface);
 
  Q_OBJECT
 
    Q_INTERFACES(SimPluginInterface);
 

	
 
public:
 
	virtual QString ModelID(void) { return QString( "Meinhardt 1976, with growth" ); }
 
 public:
 
  virtual QString ModelID(void) { return QString( "Meinhardt 1976, with growth" ); }
 
	
 
	// Executed after the cellular mechanics steps have equillibrized
 
	virtual void CellHouseKeeping (CellBase *c);
 
	// Differential equations describing transport of chemicals from cell to cell
 
	virtual void CelltoCellTransport(Wall *w, double *dchem_c1, double *dchem_c2);
 
  // Executed after the cellular mechanics steps have equillibrized
 
  virtual void CellHouseKeeping (CellBase *c);
 
  // Differential equations describing transport of chemicals from cell to cell
 
  virtual void CelltoCellTransport(Wall *w, double *dchem_c1, double *dchem_c2);
 
    
 
	// Differential equations describing chemical reactions taking place at or near the cell walls
 
	// (e.g. PIN accumulation)
 
	virtual void WallDynamics(Wall *w, double *dw1, double *dw2);
 
  // Differential equations describing chemical reactions taking place at or near the cell walls
 
  // (e.g. PIN accumulation)
 
  virtual void WallDynamics(Wall *w, double *dw1, double *dw2);
 
	
 
	// Differential equations describing chemical reactions inside the cells
 
	virtual void CellDynamics(CellBase *c, double *dchem);
 
  // Differential equations describing chemical reactions inside the cells
 
  virtual void CellDynamics(CellBase *c, double *dchem);
 
	
 
	// to be executed after a cell division
 
	virtual void OnDivide(ParentInfo *parent_info, CellBase *daughter1, CellBase *daughter2);
 
  // to be executed after a cell division
 
  virtual void OnDivide(ParentInfo *parent_info, CellBase *daughter1, CellBase *daughter2);
 
	
 
	// to be executed for coloring a cell
 
	virtual void SetCellColor(CellBase *c, QColor *color);	
 
	// return number of chemicals
 
	virtual int NChem(void) { return 4; }
 
  // to be executed for coloring a cell
 
  virtual void SetCellColor(CellBase *c, QColor *color);	
 
  // return number of chemicals
 
  virtual int NChem(void) { return 4; }
 
};
 

	
 
#endif
 

	
 
/* finis */
src/build_models/testplugin.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <QObject>
 
#include <QtGui>
 

	
 
#include "simplugin.h"
 

	
 
#include "parameter.h"
 

	
 
#include "wallbase.h"
 
#include "cellbase.h"
 
#include "testplugin.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
bool batch = false;
 

	
 
// To be executed after cell division
 
void TestPlugin::OnDivide(ParentInfo *parent_info, CellBase *daughter1, CellBase *daughter2) {
 
  parent_info = NULL;
 
  daughter1 = daughter2 = NULL;
 
}
 

	
 
void TestPlugin::SetCellColor(CellBase *c, QColor *color) { 
 

	
 
	static QStringList colors;
 
	if (colors.size()==0) {
 
		colors << "red" << "green" << "blue";
 
	}
 
	color->setNamedColor(colors[c->Index()%colors.size()]);
 
  static QStringList colors;
 
  if (colors.size()==0) {
 
    colors << "red" << "green" << "blue";
 
  }
 
  color->setNamedColor(colors[c->Index()%colors.size()]);
 
}
 

	
 

	
 

	
 
void TestPlugin::CellHouseKeeping(CellBase *c) {
 
	
 
	c->EnlargeTargetArea(par->cell_expansion_rate);
 
	if (c->Area() > par->rel_cell_div_threshold * c->BaseArea() ) {
 
		c->Divide();
 
	}
 
  c->EnlargeTargetArea(par->cell_expansion_rate);
 
  if (c->Area() > par->rel_cell_div_threshold * c->BaseArea() ) {
 
    c->Divide();
 
  }
 
}
 

	
 
void TestPlugin::CelltoCellTransport(Wall *w, double *dchem_c1, double *dchem_c2) {
 
  w = NULL;
 
  dchem_c1 = dchem_c2 = NULL;
 
}
 

	
 
void TestPlugin::WallDynamics(Wall *w, double *dw1, double *dw2) {
 
  w = NULL;
 
  dw1 = dw2 = NULL;
 
}
 

	
 
void TestPlugin::CellDynamics(CellBase *c, double *dchem) {
 
  c = NULL;
 
  dchem=NULL;
 
}
 

	
 
Q_EXPORT_PLUGIN2(testplugin, TestPlugin)
 

	
 
/* finis */
src/build_models/testplugin.h
Show inline comments
 
/*
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#ifndef _TESTPLUGIN_H_
 
#define _TESTPLUGIN_H_
 

	
 
#include <QObject>
 
#include <QtGui>
 
#include <QString>
 
#include "../simplugin.h"
 

	
 

	
 
class TestPlugin : public QObject, SimPluginInterface {
 
	Q_OBJECT
 
	Q_INTERFACES(SimPluginInterface);
 
  Q_OBJECT
 
  Q_INTERFACES(SimPluginInterface);
 

	
 
public:
 
	virtual QString ModelID(void) { return QString( "Test model" ); }
 
 public:
 
  virtual QString ModelID(void) { return QString( "Test model" ); }
 
	
 
	// Executed after the cellular mechanics steps have equillibrized
 
	virtual void CellHouseKeeping (CellBase *c);
 
	// Differential equations describing transport of chemicals from cell to cell
 
	virtual void CelltoCellTransport(Wall *w, double *dchem_c1, double *dchem_c2);
 
  // Executed after the cellular mechanics steps have equillibrized
 
  virtual void CellHouseKeeping (CellBase *c);
 
  // Differential equations describing transport of chemicals from cell to cell
 
  virtual void CelltoCellTransport(Wall *w, double *dchem_c1, double *dchem_c2);
 
    
 
	// Differential equations describing chemical reactions taking place at or near the cell walls
 
	// (e.g. PIN accumulation)
 
	virtual void WallDynamics(Wall *w, double *dw1, double *dw2);
 
  // Differential equations describing chemical reactions taking place at or near the cell walls
 
  // (e.g. PIN accumulation)
 
  virtual void WallDynamics(Wall *w, double *dw1, double *dw2);
 
	
 
	// Differential equations describing chemical reactions inside the cells
 
	virtual void CellDynamics(CellBase *c, double *dchem);
 
  // Differential equations describing chemical reactions inside the cells
 
  virtual void CellDynamics(CellBase *c, double *dchem);
 
	
 
	// to be executed after a cell division
 
	virtual void OnDivide(ParentInfo *parent_info, CellBase *daughter1, CellBase *daughter2);
 
  // to be executed after a cell division
 
  virtual void OnDivide(ParentInfo *parent_info, CellBase *daughter1, CellBase *daughter2);
 
	
 
	// to be executed for coloring a cell
 
	virtual void SetCellColor(CellBase *c, QColor *color);	
 
	// return number of chemicals
 
	virtual int NChem(void) { return 0; }
 
  // to be executed for coloring a cell
 
  virtual void SetCellColor(CellBase *c, QColor *color);	
 
  // return number of chemicals
 
  virtual int NChem(void) { return 0; }
 
};
 

	
 
#endif
 

	
 
/* finis */
src/build_models/translate_plugin.pl
Show inline comments
 
#!/usr/bin/perl
 

	
 
$cfilename = shift(@ARGV) || die "Usage: translate_plugin.pl [cfile] [hfile] [profile]\n";
 
$hfilename = shift(@ARGV) || die "Usage: translate_plugin.pl [cfile] [hfile] [profile]\n";
 
$pfilename = shift(@ARGV) || die "Usage: translate_plugin.pl [cfile] [hfile] [profile]\n";
 

	
 
$ocfname = $cfilename; $ocfname =~ s/\.cpp/_tl.cpp/g;
 
$ohfname = $hfilename; $ohfname =~ s/\.h/_tl.h/g;
 
$opfname = $pfilename; $opfname =~ s/\.pro/_tl.pro/g;
 

	
 
print STDERR "Translating '$cfilename' to '$ocfname', '$hfilename' to '$ohfname', and '$pfilename' to '$opfname'\n";
 

	
 
open cfile,"<$cfilename";
 
open ocfile,">$ocfname";
 

	
 
while (<cfile>) {
 
	
 
	#s/$hfilename/$ohfname/g;
 
    
 
    #s/$hfilename/$ohfname/g;
 
    
 
    # translate function definitions
 
    if (/[a-zA-Z0-9 ]*::OnDivide/) {
 
	s/ParentInfo &parent_info/ParentInfo *parent_info/g;
 
	s/CellBase &daughter1/CellBase *daughter1/g;
 
	s/CellBase &daughter2/CellBase *daughter2/g;
 
    }
 
    
 
	# translate function definitions
 
	if (/[a-zA-Z0-9 ]*::OnDivide/) {
 
		s/ParentInfo &parent_info/ParentInfo *parent_info/g;
 
		s/CellBase &daughter1/CellBase *daughter1/g;
 
		s/CellBase &daughter2/CellBase *daughter2/g;
 
	}
 
	
 
	if (/[a-zA-Z0-9 ]*::SetCellColor/) {
 
		s/CellBase &c/CellBase *c/g;
 
		s/QColor &color/QColor *color/g;
 
	}
 
	
 
	if (/[a-zA-Z0-9 ]*::CellHouseKeeping/) {
 
		s/CellBase &c/CellBase *c/g;
 
	}
 
	
 
	# translate member function calls
 
	s/\bparent_info\b\./parent_info->/g;
 
	s/\bdaughter1\b\./daughter1->/g;
 
	s/\bdaughter2\b\./daughter2->/g;
 
	s/\bc\b\./c->/g;
 
	s/\bcolor\b\./color->/g;
 
	print ocfile;
 
	
 
    if (/[a-zA-Z0-9 ]*::SetCellColor/) {
 
	s/CellBase &c/CellBase *c/g;
 
	s/QColor &color/QColor *color/g;
 
    }
 
    
 
    if (/[a-zA-Z0-9 ]*::CellHouseKeeping/) {
 
	s/CellBase &c/CellBase *c/g;
 
    }
 
    
 
    # translate member function calls
 
    s/\bparent_info\b\./parent_info->/g;
 
    s/\bdaughter1\b\./daughter1->/g;
 
    s/\bdaughter2\b\./daughter2->/g;
 
    s/\bc\b\./c->/g;
 
    s/\bcolor\b\./color->/g;
 
    print ocfile;
 
    
 
}
 

	
 
open hfile,"<$hfilename";
 
open ohfile,">$ohfname";
 

	
 
while (<hfile>) {
 
	if (/[ \t]*virtual[ \t]+void[ \t]+CellHouseKeeping/) {
 
		s/CellBase &c/CellBase *c/g;
 
	}
 
	if (/[ \t]*virtual[ \t]+void[ \t]+OnDivide/) {
 
		s/ParentInfo &parent_info/ParentInfo *parent_info/g;
 
		s/CellBase &daughter1/CellBase *daughter1/g;
 
		s/CellBase &daughter2/CellBase *daughter2/g;
 
	}
 
	if (/[ \t]*virtual[ \t]+void[ \t]+SetCellColor/) {
 
		s/CellBase &c/CellBase *c/g;
 
		s/QColor &color/QColor *color/g;
 
	}
 
	
 
	
 
	print ohfile;
 
	
 
    if (/[ \t]*virtual[ \t]+void[ \t]+CellHouseKeeping/) {
 
	s/CellBase &c/CellBase *c/g;
 
    }
 
    if (/[ \t]*virtual[ \t]+void[ \t]+OnDivide/) {
 
	s/ParentInfo &parent_info/ParentInfo *parent_info/g;
 
	s/CellBase &daughter1/CellBase *daughter1/g;
 
	s/CellBase &daughter2/CellBase *daughter2/g;
 
    }
 
    if (/[ \t]*virtual[ \t]+void[ \t]+SetCellColor/) {
 
	s/CellBase &c/CellBase *c/g;
 
	s/QColor &color/QColor *color/g;
 
    }
 
    
 
    
 
    print ohfile;
 
    
 
}
 

	
 
open pfile,"<$pfilename";
 
open opfile,">$opfname";
 

	
 
while (<pfile>) {
 
	
 
	s/\bplugin\b\.h/plugin_tl\.h/g;
 
	s/\bplugin\b\.cpp/plugin_tl\.cpp/g;
 
	
 
	print opfile;
 
	
 
}
 
\ No newline at end of file
 
    
 
    s/\bplugin\b\.h/plugin_tl\.h/g;
 
    s/\bplugin\b\.cpp/plugin_tl\.cpp/g;
 
    
 
    print opfile;
 
    
 
}
 

	
 
#finis
src/canvas.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <QDebug>
 

	
 
#include <string>
 
#include <QGraphicsScene>
 
#include <QGraphicsView>
 
#include <qdatetime.h>
 
#include <q3mainwindow.h>
 
#include <qstatusbar.h>
 
#include <qmessagebox.h>
 
#include <qmenubar.h>
 
#include <qapplication.h>
 
#include <qpainter.h>
 
#include <qprinter.h>
 
#include <qlabel.h>
 
#include <qimage.h>
 
#include <q3progressdialog.h>
 
#include <qtimer.h>
 
#include <qslider.h>
 
#include <qpixmap.h>
 
#include <qfile.h>
 
#include <qdir.h>
 
#include <q3filedialog.h>
 
#include <QGraphicsItem>
 
#include <QList>
 
#include <QDebug>
 

	
 
#include <set>
 

	
 
//Added by qt3to4:
 
#include <Q3ValueList>
 
#include <Q3PopupMenu>
 
#include <QMouseEvent>
 
#include <typeinfo>
 
#include <cstring>
 
#include <q3process.h>
 
#include <qlayout.h>
 
#include <qspinbox.h>
 
#include <fstream>
 
#include <sstream>
 
#include "pardialog.h"
 
#include "parameter.h"
 
#include "canvas.h"
 
#include "node.h"
 
#include "nodeset.h"
 
#include "nodeitem.h"
 
#include "cellitem.h"
 
#include "wallitem.h"
 
#include "mesh.h"
 
#include "xmlwrite.h"
 
#include "miscq.h"
 
#include "OptionFileDialog.h"
 
#include <cstdlib>
 
#include <cstdio>
 
#include "modelcatalogue.h"
 

	
 
#include <algorithm>
 

	
 
// Include VIB and PSB logos
 
#include "psb.xpm"
 
#include "cwi.xpm"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
// We use a global variable to save memory - all the brushes and pens in
 
// the mesh are shared.
 

	
 
#define QUOTE_ME(s) QUOTE_ME_2NDLEV(s)
 
#define QUOTE_ME_2NDLEV(s) #s
 

	
 
static QColor dark_red("darkRed");
 

	
 

	
 
static const int imageRTTI = 984376;
 
extern Parameter par;
 
const QString Main::caption("Virtual leaf");
 
const QString Main::caption_with_file("Virtual leaf: %1");
 

	
 
FigureEditor::FigureEditor(
 
			   QGraphicsScene& c, Mesh &m, QWidget* parent,
 
			   const char* name, Qt::WindowFlags f) :
 
  QGraphicsView(&c,parent), mesh(m)
 
{
 
  name = NULL; // use these two assignments merely to obviate compile time warnings
 
  f = Qt::Widget;
 

	
 
  intersection_line = 0;
 
  //angle_line = 0;
 
  setInteractive(true);
 
  moving = 0;  
 
  rotation_mode = false;
 
}
 

	
 

	
 
void FigureEditor::clear()
 
{
 
  QList<QGraphicsItem *> list = scene()->items();
 
  QList<QGraphicsItem *>::Iterator it = list.begin();
 
  for (; it != list.end(); ++it) {
 
    delete *it;
 
  }
 
}
 

	
 
 void FigureEditor::wheelEvent(QWheelEvent *event)
 
 {
 
   scaleView(pow((double)2, -event->delta() / 240.0));
 
 }
 
void FigureEditor::wheelEvent(QWheelEvent *event)
 
{
 
  scaleView(pow((double)2, -event->delta() / 240.0));
 
}
 

	
 

	
 
void FigureEditor::scaleView (qreal scaleFactor)
 
{
 
  qreal factor = matrix().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)). width();
 
  if (factor < 0.07 || factor > 100) return;
 
  scale (scaleFactor, scaleFactor);
 
}
 

	
 
void FigureEditor::Save(const char *fname, const char *format, int sizex, int sizey) {
 
  
 
    QImage *image = new QImage(sizex, sizey, QImage::Format_RGB32);
 
    image->fill(QColor(Qt::white).rgb());
 
    QPainter *painter=new QPainter(image);
 
    
 
    render(painter);
 
    
 
    image->save(QString(fname),format);
 
    delete painter;
 
    delete image;
 
void FigureEditor::Save(const char *fname, const char *format, int sizex, int sizey)
 
{
 

	
 
  QImage *image = new QImage(sizex, sizey, QImage::Format_RGB32);
 
  image->fill(QColor(Qt::white).rgb());
 
  QPainter *painter=new QPainter(image);
 

	
 
  render(painter);
 

	
 
  image->save(QString(fname),format);
 
  delete painter;
 
  delete image;
 
}
 

	
 
//void FigureEditor::contentsMousePressEvent(QMouseEvent* e)
 
void FigureEditor::mousePressEvent(QMouseEvent* e)
 
{
 
  static QList<Node*> selected;
 
  emit MousePressed();
 

	
 
  //QPointF p = matrix().inverted().map(e->pos());
 
  QPointF p = mapToScene(e->pos());
 

	
 
#ifdef QDEBUG  
 
  qDebug() << endl << "MousePressEvent location: (" << p.x() << "," << p.y() << ")." << endl;
 
  qDebug() << "Magnification:  " << Cell::Magnification() << endl;
 
  qDebug() << "Offsets:  " << Cell::Offset() << endl;
 
#endif
 
  
 

	
 

	
 
  QList<QGraphicsItem *> l=scene()->items(p);
 

	
 
#ifdef QDEBUG  
 
  qDebug() << "MousePressEvents, items: " << l.size() << endl;
 
  qDebug() << "Mouse button modifier: " << e->modifiers() << endl;
 
#endif
 

	
 
    if (e->button()==Qt::RightButton || l.size()==0) {
 
    
 
      //cerr << "Drawing an intersection line from " << p.x() << ", " << p.y() << endl;
 
      intersection_line = new QGraphicsLineItem( 0, scene() );
 
      intersection_line->setPen( QPen( QColor("red"), 3, Qt::DashLine ) );
 
      intersection_line->setLine( QLineF(p,p) );
 
      intersection_line->setZValue( 100 );
 
      intersection_line->show();
 
    }
 
  
 
    for (QList<QGraphicsItem *>::Iterator it=l.begin(); it!=l.end(); ++it) {
 
      #ifdef QDEBUG
 
      qDebug() << typeid(**it).name() << endl;
 
      #endif
 
  if (e->button()==Qt::RightButton || l.size()==0) {
 

	
 
    //cerr << "Drawing an intersection line from " << p.x() << ", " << p.y() << endl;
 
    intersection_line = new QGraphicsLineItem( 0, scene() );
 
    intersection_line->setPen( QPen( QColor("red"), 3, Qt::DashLine ) );
 
    intersection_line->setLine( QLineF(p,p) );
 
    intersection_line->setZValue( 100 );
 
    intersection_line->show();
 
  }
 

	
 
  for (QList<QGraphicsItem *>::Iterator it=l.begin(); it!=l.end(); ++it) {
 
#ifdef QDEBUG
 
    qDebug() << typeid(**it).name() << endl;
 
#endif
 

	
 
    if ( !strcmp(typeid(**it).name(),"8NodeItem")) {
 

	
 
      if ( !strcmp(typeid(**it).name(),"8NodeItem")) {
 
      
 
	stringstream data_strstream;
 
	data_strstream << (dynamic_cast<NodeItem*>(*it))->getNode();
 
	dynamic_cast<Main *>(parent())->UserMessage(QString(data_strstream.str().c_str()));
 
      
 
	(dynamic_cast<NodeItem*>(*it))->OnClick(e->button());
 
      stringstream data_strstream;
 
      data_strstream << (dynamic_cast<NodeItem*>(*it))->getNode();
 
      dynamic_cast<Main *>(parent())->UserMessage(QString(data_strstream.str().c_str()));
 

	
 
      (dynamic_cast<NodeItem*>(*it))->OnClick(e->button());
 
    }
 
    else 
 
      if ( !strcmp(typeid(**it).name(),"8CellItem") ) {
 

	
 
	Cell &c=((dynamic_cast<CellItem *>(*it))->getCell());      
 
	// OnClick to be defined in end-user code
 
	c.OnClick(e);
 
      } else {
 
	if ( !strcmp(typeid(**it).name(),"8WallItem") ) {
 
	  (dynamic_cast<WallItem *>(*it))->OnClick(e);
 
	} 
 
      }
 
      else 
 
	if ( !strcmp(typeid(**it).name(),"8CellItem") ) {
 
      
 
	  Cell &c=((dynamic_cast<CellItem *>(*it))->getCell());      
 
	  // OnClick to be defined in end-user code
 
	  c.OnClick(e);
 
	} else {
 
	  if ( !strcmp(typeid(**it).name(),"8WallItem") ) {
 
	    (dynamic_cast<WallItem *>(*it))->OnClick(e);
 
	  } 
 
	}
 
    }
 
  }
 

	
 
  FullRedraw();
 
  moving = 0;
 
}
 
  
 
//void FigureEditor::contentsMouseMoveEvent(QMouseEvent* e)
 

	
 
void FigureEditor::mouseMoveEvent(QMouseEvent* e)
 
{
 

	
 
  // User choose "rotation mode" and we can rotate the object around its center of mass
 
  if (dynamic_cast<Main *>(parent())->RotationModeP()) {
 

	
 
    QPointF p = mapToScene(e->pos());
 
    p.setX(p.x() / Cell::Magnification());
 
    p.setY(p.y() / Cell::Magnification());
 

	
 

	
 
    // get object's center of mass
 
    QPointF rotation_midpoint = mesh.Centroid()*Cell::Factor() - Cell::Offset();
 
    
 
        
 

	
 

	
 
    // calculate rotation angle
 
    double dy = (rotation_midpoint.y() - p.y());
 
    double dx = (rotation_midpoint.x() - p.x());
 
    double new_rot_angle = atan2(dx, dy);
 
    double d_alpha = new_rot_angle - rot_angle;
 
    rot_angle = new_rot_angle;
 
    
 

	
 
    mesh.Rotate(d_alpha, ( Vector(rotation_midpoint) + Cell::Offset() ) / Cell::Factor() );
 
    
 

	
 
    dynamic_cast<Main *>(parent())->Plot(0);
 
	  FullRedraw();
 
    FullRedraw();
 
    return;
 
  }
 
  if ( moving ) {
 

	
 
    QPointF p = mapToScene(e->pos());
 
    moving->userMove(p.x() - moving_start.x(),
 
		     p.y() - moving_start.y());
 
    moving_start = p;
 
    scene()->update();
 
    
 

	
 
  }
 
  
 

	
 
  //cerr << "event";
 
  
 

	
 
  // keep track of intersection line to interactively cut a growing leaf
 
    
 

	
 
  if ( intersection_line ) {
 
    
 

	
 
    QPointF sp = intersection_line -> line().p1(); // startpoint
 
    QPointF ep = mapToScene(e->pos()); // endpoint
 
    intersection_line -> setLine( QLineF(sp, ep) ); 
 
    scene()->update();
 
    // Need this for Mac
 
    FullRedraw();
 
    }
 
  }
 
}
 

	
 
//void FigureEditor::contentsMouseReleaseEvent(QMouseEvent* e)
 
void FigureEditor::mouseReleaseEvent(QMouseEvent* e)
 
{
 
  
 

	
 
  emit MouseReleased();
 
  // intersection line for leaf was finished now.
 
  
 

	
 
  if (e->button()==Qt::LeftButton) { 
 
    if (intersection_line ) {
 
      #ifdef QDEBUG
 
#ifdef QDEBUG
 
      qDebug() << "Trying to cut leaf" << endl;
 
      #endif
 
#endif
 
      QPointF sp = intersection_line -> line().p1(); // startpoint
 
      QPointF ep = mapToScene(e->pos());
 

	
 
      intersection_line -> setLine( QLineF(sp, ep) ); 
 
      intersection_line -> show();
 

	
 
      vector <CellItem *> intersected_cells = getIntersectedCells();
 
    
 

	
 
      // no cells selected, do nothing
 
      if (intersected_cells.size()==0) {
 
        #ifdef QDEBUG
 
#ifdef QDEBUG
 
	qDebug() << "No cells detected :-(" << endl;
 
	#endif
 
#endif
 
	return;
 
      }
 
      
 
    
 

	
 

	
 
      Vector startpoint = Vector(sp.x(), sp.y()) / Cell::Factor() - Cell::Offset();
 
      Vector endpoint = Vector(ep.x(), ep.y()) / Cell::Factor() - Cell::Offset();
 
    
 

	
 
      NodeSet *node_set = new NodeSet;
 
      
 

	
 
      for (vector<CellItem *>::iterator it = intersected_cells.begin();
 
	   it != intersected_cells.end();
 
	   it++) {
 
      
 

	
 
	(*it)->setBrush(QBrush("purple"));
 
       
 

	
 
	Cell &c=(*it)->getCell();
 
      
 

	
 
	// sometimes the cell hasn't properly divided yet before the
 
	// next division is called?  so check for it?  let's find a way
 
	// to do this later. Note that this functionality currently
 
	// might result in a segmentation fault for users who are
 
	// quickly dragging and releasing division lines...
 
	scene()->update();
 
	
 
	#ifdef QDEBUG
 

	
 
#ifdef QDEBUG
 
	qDebug() << "Dividing Cell " << c.Index() << endl;
 
	#endif
 
#endif
 

	
 
	c.DivideOverGivenLine( startpoint, endpoint, true, node_set);
 
      }
 
      
 

	
 
      node_set->CleanUp();
 
      mesh.AddNodeSet(node_set);
 
      
 
      #ifdef QDEBUG
 

	
 
#ifdef QDEBUG
 
      qDebug() << "Done DivideOverGivenLine" << endl;
 
      #endif
 
#endif
 

	
 
      mesh.TestIllegalWalls();
 
      // Do the actual cutting and removing
 
      if (intersected_cells.size()) {
 
	mesh.CutAwayBelowLine( startpoint, endpoint ); 
 
	
 

	
 
	// Correct flags of nodeset
 
	for (
 
	     NodeSet::iterator i = node_set->begin(); 
 
	     i != node_set->end();
 
	     i++) {
 
	  (*i)->SetSAM();
 
	  (*i)->SetBoundary();
 
	}
 

	
 
	// Make cells attached to nodeset part of the boundary
 
	// This is a temporary solution for the following:
 
	//   If a cell attached to a NodeSet divides (with a division plane intersecting the node set), 
 
	//   we must insert a new node into the node set.
 
	// For now, we add a layer of "virtual cells" inbetween. 
 
	list<Cell *> cells_attached_to_nodeset = node_set->getCells();
 
	for ( list<Cell *>::iterator c = cells_attached_to_nodeset.begin();
 
	      c != cells_attached_to_nodeset.end(); 
 
	      c++) {
 
	  (*c)->SetBoundary(Cell::SAM);
 
	}
 

	
 

	
 

	
 
	#ifdef QDEBUG
 
#ifdef QDEBUG
 
	qDebug() << "Done CutAwayBelowLine" << endl;
 
	#endif
 
#endif
 
	mesh.TestIllegalWalls();
 
	mesh.RepairBoundaryPolygon();
 
	#ifdef QDEBUG
 
#ifdef QDEBUG
 
	qDebug() << "Done RepairBoundaryPolygon" << endl;
 
	#endif
 
#endif
 
	mesh.TestIllegalWalls();
 
	mesh.CleanUpWalls();
 
	#ifdef QDEBUG
 
#ifdef QDEBUG
 
	qDebug() << "Done CleanUpWalls" << endl;
 
	#endif
 
#endif
 
	mesh.TestIllegalWalls();
 
      }
 
      
 

	
 
      dynamic_cast<Main *>(parent())->Plot();
 
      
 
        #ifdef QDEBUG
 
	qDebug() << "NodeSet of cutting line: " << *node_set << endl;
 
	#endif
 

	
 
#ifdef QDEBUG
 
      qDebug() << "NodeSet of cutting line: " << *node_set << endl;
 
#endif
 
    }
 
  } else 
 
    if (e->button()==Qt::RightButton) {
 
      
 

	
 
      if (intersection_line /* && !angle_line*/) {
 
	
 

	
 
	QPointF p = mapToScene(e->pos());
 
	QPointF sp = intersection_line->line().p1();
 
	
 

	
 
	viewport()->setMouseTracking( TRUE );
 
      } 
 
    }
 
}
 

	
 

	
 
// returns a vector of pointer to cells colliding with intersection line
 
vector <CellItem *> FigureEditor::getIntersectedCells(void) { 
 
  
 
vector <CellItem *> FigureEditor::getIntersectedCells(void)
 
{ 
 
  vector <CellItem *> colliding_cells;
 
  
 

	
 
  QList<QGraphicsItem *> l = intersection_line->collidingItems( );
 
  
 
  #ifdef QDEBUG
 

	
 
#ifdef QDEBUG
 
  qDebug() <<  "l.size() = " << l.size() << endl;
 
  #endif
 
#endif
 

	
 
  for (QList<QGraphicsItem *>::Iterator it=l.begin(); it!=l.end(); ++it) {
 
    
 
    #ifdef QDEBUG
 

	
 
#ifdef QDEBUG
 
    qDebug() << typeid(**it).name() << endl;
 
    #endif
 
    
 
#endif
 

	
 
    if ( !strcmp(typeid(**it).name(),"8CellItem") ) {
 
      colliding_cells.push_back(dynamic_cast<CellItem *>(*it));
 
    }
 
  }
 
  
 

	
 
  delete intersection_line;
 
  intersection_line = 0;
 
  return colliding_cells;
 
    
 
}
 

	
 
void FigureEditor::FullRedraw(void) {
 
	QList<QRectF> rl;
 
	rl << sceneRect();
 
	updateScene(rl);   
 
void FigureEditor::FullRedraw(void)
 
{
 
  QList<QRectF> rl;
 
  rl << sceneRect();
 
  updateScene(rl);   
 
}
 

	
 

	
 
NodeItem *FigureEditor::selectedNodeItem(QList<QGraphicsItem *> graphicItems) const
 
{
 
  NodeItem *nodeItem = 0;
 
  // graphicItems is a list of the QgraphicItems under the mouse click event 
 
  QList<QGraphicsItem *>::Iterator it = graphicItems.begin();
 
  for (; it != graphicItems.end(); ++it) {
 
    if ( !strcmp(typeid(**it).name(),"8NodeItem")) {
 
      // the object under the mouse click is a Nodeitem
 
      nodeItem = dynamic_cast<NodeItem *>(*it);
 
      // indicate we've selected it
 
      nodeItem->setBrush(dark_red);
 
      break;
 
    }
 
  }
 
  return nodeItem;
 
}
 

	
 

	
 
void FigureEditor::insertNode(QPointF p)
 
{
 
  Node *node = new Node(p.x(), p.y(), 0);
 
  mesh.AddNode(node);
 
  scene()->clearSelection();
 
  dynamic_cast<Main *>(parent())->Plot();
 
  FullRedraw();
 
#ifdef QDEBUG  
 
  qDebug() << "Node: " << p << endl;
 
#endif
 
}
 

	
 
static uint mainCount = 0;
 

	
 
Main::Main(QGraphicsScene& c, Mesh &m, QWidget* parent, const char* name, Qt::WindowFlags f) :
 
  Q3MainWindow(parent,name,f),
 
  MainBase(c,m),
 
  mesh(m)
 
{
 
  editor = new FigureEditor(canvas,mesh, this);
 

	
 
  #ifdef QDEBUG
 
#ifdef QDEBUG
 
  qDebug() << "Interactive = " << editor->isEnabled();
 
  #endif
 
#endif
 

	
 
  working_dir = 0;
 
  QObject::connect( editor, SIGNAL(MousePressed()), this, SLOT(PauseIfRunning()));
 
  QObject::connect( editor, SIGNAL(MouseReleased()), this, SLOT(ContIfRunning()));
 
  QMenuBar* menu = menuBar();
 
  
 

	
 
  Q3PopupMenu* file = new Q3PopupMenu( menu );
 

	
 
	file->insertItem("&Read leaf", this, SLOT(readStateXML()));
 
	file->insertItem("&Save leaf", this, SLOT(saveStateXML()));
 
	file->insertItem("Snapshot", this, SLOT(snapshot()), Qt::CTRL+Qt::SHIFT+Qt::Key_S);
 
  file->insertItem("&Read leaf", this, SLOT(readStateXML()));
 
  file->insertItem("&Save leaf", this, SLOT(saveStateXML()));
 
  file->insertItem("Snapshot", this, SLOT(snapshot()), Qt::CTRL+Qt::SHIFT+Qt::Key_S);
 

	
 
  file->insertSeparator();
 
  file->insertItem("Read next leaf", this, SLOT(readNextStateXML()), Qt::Key_PageDown);
 
  file->insertItem("Read previous leaf", this, SLOT(readPrevStateXML()), Qt::Key_PageUp);
 
  file->insertItem("Read last leaf", this, SLOT(readLastStateXML()), Qt::Key_End);
 
  file->insertItem("Read first leaf", this, SLOT(readFirstStateXML()), Qt::Key_Home);
 

	
 
   file->insertSeparator();
 
	file->insertItem("Read next leaf", this, SLOT(readNextStateXML()), Qt::Key_PageDown);
 
	file->insertItem("Read previous leaf", this, SLOT(readPrevStateXML()), Qt::Key_PageUp);
 
	file->insertItem("Read last leaf", this, SLOT(readLastStateXML()), Qt::Key_End);
 
	file->insertItem("Read first leaf", this, SLOT(readFirstStateXML()), Qt::Key_Home);
 
	
 
	file->insertSeparator();
 
	file->insertItem("&Print...", this, SLOT(print()), Qt::CTRL+Qt::Key_P);
 
	file->insertSeparator();
 
	file->insertItem("E&xit", qApp, SLOT(quit()), Qt::CTRL+Qt::Key_Q);
 
	menu->insertItem("&File", file);
 
	
 
	Q3PopupMenu* edit = new Q3PopupMenu( menu );
 
  file->insertSeparator();
 
  file->insertItem("&Print...", this, SLOT(print()), Qt::CTRL+Qt::Key_P);
 
  file->insertSeparator();
 
  file->insertItem("E&xit", qApp, SLOT(quit()), Qt::CTRL+Qt::Key_Q);
 
  menu->insertItem("&File", file);
 

	
 
  Q3PopupMenu* edit = new Q3PopupMenu( menu );
 
  edit->insertItem("Reset Chemicals and Transporters", this, SLOT( CleanMesh()), Qt::CTRL+Qt::Key_R );
 
	edit->insertItem("Reset Chemicals", this, SLOT( CleanMeshChemicals()) );
 
	edit->insertItem("Reset Transporters", this, SLOT( CleanMeshTransporters()) );
 
  edit->insertItem("Reset Chemicals", this, SLOT( CleanMeshChemicals()) );
 
  edit->insertItem("Reset Transporters", this, SLOT( CleanMeshTransporters()) );
 
  edit->insertItem("Randomize PIN1 Transporters", this, SLOT( RandomizeMesh()) );
 
  edit->insertItem("Cut away SAM", this, SLOT( CutSAM() ));
 
  menu->insertItem("&Edit", edit);
 

	
 
  run = new Q3PopupMenu( menu );
 
  running = false;
 
	paused_id = run->insertItem("&Simulation paused", this, SLOT(togglePaused()), Qt::Key_S);
 
  paused_id = run->insertItem("&Simulation paused", this, SLOT(togglePaused()), Qt::Key_S);
 
  run->setItemChecked(paused_id, FALSE);
 

	
 
  menu->insertItem("&Run", run);
 
  
 

	
 
  view = new Q3PopupMenu( menu );
 
	view->insertItem("&Zoom in", this, SLOT(zoomIn()), Qt::CTRL+Qt::Key_Equal);
 
  view->insertItem("&Zoom in", this, SLOT(zoomIn()), Qt::CTRL+Qt::Key_Equal);
 
  view->insertItem("Zoom &out", this, SLOT(zoomOut()), Qt::CTRL+Qt::Key_Minus);
 
	view->insertSeparator();
 
	com_id = view->insertItem("Show cell &centers", this, SLOT(toggleShowCellCenters()));
 
  view->insertSeparator();
 
  com_id = view->insertItem("Show cell &centers", this, SLOT(toggleShowCellCenters()));
 
  view->setItemChecked(com_id, FALSE);
 

	
 
  mesh_id = view->insertItem("Show &nodes", this, SLOT(toggleShowNodes()), Qt::CTRL+Qt::SHIFT+Qt::Key_N);
 
  view->setItemChecked(mesh_id, TRUE);
 
  node_number_id = view->insertItem("Show node numbers", this, SLOT(toggleNodeNumbers()), Qt::CTRL+Qt::SHIFT+Qt::Key_M);
 
  view->setItemChecked(node_number_id, FALSE);
 
  cell_number_id = view->insertItem("Show cell numbers", this, SLOT(toggleCellNumbers()));
 
  view->setItemChecked(cell_number_id, FALSE);
 
  hide_cells_id = view->insertItem("Hide cells", this, SLOT(toggleHideCells()));
 
  view->setItemChecked(hide_cells_id, FALSE);
 
  border_id = view->insertItem("Show &border cells", this, SLOT(toggleShowBorderCells()));
 
  view->setItemChecked(border_id, FALSE);
 
  cell_axes_id = view->insertItem("Show cell &axes", this, SLOT(toggleCellAxes()));
 
  cell_strain_id = view->insertItem("Show cell &strain", this, SLOT(toggleCellStrain()));
 
  view->setItemChecked(cell_axes_id, FALSE);
 
  fluxes_id = view->insertItem("Show &fluxes", this, SLOT(toggleShowFluxes()));
 
  view->setItemChecked(fluxes_id, FALSE);
 
  cell_walls_id = view->insertItem("Show transporters", this, SLOT(toggleShowWalls()));
 
	view->setItemChecked(cell_walls_id, FALSE);
 
	apoplasts_id = view->insertItem("Show apoplasts", this, SLOT(toggleShowApoplasts()));
 
  view->setItemChecked(cell_walls_id, FALSE);
 
  apoplasts_id = view->insertItem("Show apoplasts", this, SLOT(toggleShowApoplasts()));
 
  view->setItemChecked(apoplasts_id, FALSE);
 
 	view->insertSeparator();
 
	  only_boundary_id = view->insertItem("Show only leaf &boundary", this, SLOT(toggleLeafBoundary()));
 
	view->insertSeparator();
 
	movie_frames_id = view->insertItem("Start saving movie &frames", this, SLOT(toggleMovieFrames()));
 
  view->insertSeparator();
 
  only_boundary_id = view->insertItem("Show only leaf &boundary", this, SLOT(toggleLeafBoundary()));
 
  view->insertSeparator();
 
  movie_frames_id = view->insertItem("Start saving movie &frames", this, SLOT(toggleMovieFrames()));
 
  view->setItemChecked(movie_frames_id, par.movie);
 
	
 
	view->setItemChecked(only_boundary_id, FALSE);
 

	
 
  view->setItemChecked(only_boundary_id, FALSE);
 
  menu->insertItem("&View", view);
 
  
 
  
 

	
 

	
 
  options = new Q3PopupMenu( menu );
 
  dyn_cells_id = options->insertItem("Cell growth", this, SLOT(toggleDynCells()));
 
  options->setItemChecked(dyn_cells_id, true);
 

	
 
  options->insertItem("Edit &parameters", this, SLOT(EditParameters()), Qt::CTRL+Qt::Key_E);
 
  
 

	
 
  rotation_mode_id = options->insertItem("Rotate leaf", this, SLOT(EnterRotationMode()), Qt::CTRL + Qt::SHIFT + Qt::Key_R);
 
  options->setItemChecked(rotation_mode_id, false);
 

	
 
  menu->insertItem("&Options",options);
 
	
 
	// Menu of models
 
	modelmenu = new QMenu( menu );
 
	menu->insertItem("&Models", modelmenu);
 
	
 
	
 

	
 
  // Menu of models
 
  modelmenu = new QMenu( menu );
 
  menu->insertItem("&Models", modelmenu);
 

	
 

	
 
  menu->insertSeparator();
 
  
 

	
 
  helpmenu = new Q3PopupMenu( menu );
 
  tooltips_id = helpmenu->insertItem("Show Cell&Info", this, SLOT(Refresh()));
 
  helpmenu->setItemChecked(tooltips_id, true);
 
  helpmenu->insertSeparator();
 

	
 
  helpmenu->insertItem("&About", this, SLOT(help()) ); //, Key_F1);
 
  menu->insertItem("&Help",helpmenu);
 
  statusBar();
 
  setCentralWidget(editor);
 
  printer = 0;
 
  init();
 
    
 

	
 
  // Start timer which repetitively invokes
 
  // a simulation time step
 
  timer = new QTimer( this );
 
  connect( timer, SIGNAL(timeout()), SLOT(TimeStepWrap()) );
 
  
 

	
 
  stopSimulation();
 
  statusBar()->addWidget(new QLabel("Ready."));
 
  setCaption(caption);
 
  gifanim = 0;
 
	
 
	infobar = new InfoBar();
 
	addDockWindow(infobar);
 

	
 
  infobar = new InfoBar();
 
  addDockWindow(infobar);
 
}
 

	
 
void Main::RefreshInfoBar(void) {
 
	infobar->SetText(mesh.ModelID());
 
void Main::RefreshInfoBar(void)
 
{
 
  infobar->SetText(mesh.ModelID());
 
}
 

	
 

	
 
void Main::UserMessage(QString message, int timeout) {
 

	
 
void Main::UserMessage(QString message, int timeout)
 
{
 
  statusBar()->showMessage(message, timeout);
 

	
 
}
 

	
 

	
 
void Main::init()
 
{
 
  clear();
 
  
 

	
 
  static int r=24;
 
  srand(++r);
 
  
 

	
 
  mainCount++;
 
  
 
  
 
}
 

	
 
Main::~Main()
 
{
 
  delete printer;
 
  if ( !--mainCount ) {
 
  }
 
  //EndGifAnim();
 
}
 

	
 
void Main::newView()
 
{
 
  // Open a new view... have it delete when closed.
 
  Main *m = new Main(canvas, mesh, 0, 0, Qt::WDestructiveClose);
 
  qApp->setMainWidget(m);
 
  m->show();
 
  qApp->setMainWidget(0);
 
}
 

	
 

	
 
void Main::EditParameters() {
 
  
 
void Main::EditParameters()
 
{
 

	
 
  ParameterDialog *pardial = new ParameterDialog(this, "stridediag");
 

	
 
  // Make sure the values in the parameter dialog are updated after a file is read 
 
  // each method changing the parameters (reading XML or PAR files) should
 
  // emit this signal
 
  QObject::connect(   this, SIGNAL( ParsChanged() ), pardial, SLOT( Reset() ) );
 

	
 
}
 

	
 
void Main::savePars() {
 
  
 
void Main::savePars()
 
{
 

	
 
  stopSimulation();
 
  
 

	
 
  Q3FileDialog *fd = new Q3FileDialog( this, "file dialog", TRUE );
 
  fd->setMode( Q3FileDialog::AnyFile );
 
  fd->setFilter( "Parameter files (*.par)");
 

	
 
  QString fileName;
 
  if ( fd->exec() == QDialog::Accepted ) {
 
    fileName = fd->selectedFile();
 
    ofstream parfile((const char *)fileName);
 
    par.Write(parfile);
 
  }
 

	
 
  startSimulation();
 

	
 
}
 

	
 
void Main::readPars() {
 
  
 
void Main::readPars()
 
{
 

	
 
  stopSimulation();
 
  
 

	
 
  Q3FileDialog *fd = new Q3FileDialog( this, "file dialog", TRUE );
 
  fd->setMode( Q3FileDialog::ExistingFile );
 
  fd->setFilter( "Parameter files (*.par)");
 

	
 
  QString fileName;
 
  if ( fd->exec() == QDialog::Accepted ) {
 
    fileName = fd->selectedFile();
 
    par.Read((const char *)fileName);
 
  }
 
  
 

	
 
  emit ParsChanged();
 
  /* if (timer_active)
 
     timer->start( 0 );*/
 
  
 
}
 

	
 

	
 
void Main::saveStateXML() {
 
  
 
void Main::saveStateXML()
 
{
 

	
 
  stopSimulation();
 
  Q3FileDialog *fd = new Q3FileDialog( this, "file dialog", TRUE );
 
  fd->setMode( Q3FileDialog::AnyFile );
 
  fd->setFilter( "XML (*.xml)");
 
  QString fileName;
 
  
 

	
 
  if ( fd->exec() == QDialog::Accepted ) {
 
    fileName = fd->selectedFile();
 
    if ( QFile::exists( fileName ) &&
 
	 QMessageBox::question(
 
			       this,
 
			       tr("Overwrite File? -- Leaf Growth"),
 
			       tr("A file called %1 already exists."
 
				  "Do you want to overwrite it?")
 
			       .arg( fileName ),
 
			       tr("&Yes"), tr("&No"),
 
			       QString::null, 1, 1 ) ) {
 
      return saveStateXML();
 
      
 

	
 
    } else {
 
      
 

	
 
      mesh.XMLSave((const char *)fileName, XMLSettingsTree());
 
    
 

	
 
    }
 
  }
 

	
 
}
 

	
 

	
 

	
 
void Main::snapshot() {
 
  
 
   
 
void Main::snapshot()
 
{
 

	
 

	
 
  stopSimulation();
 
  Q3FileDialog *fd = new Q3FileDialog( this, "Save snapshot", TRUE );
 
  fd->setMode( Q3FileDialog::AnyFile );
 
  
 

	
 
  QString fileName;
 
  
 

	
 
  if ( fd->exec() == QDialog::Accepted ) {
 
    fileName = fd->selectedFile();
 
    if ( QFile::exists( fileName ) &&
 
	 QMessageBox::question(
 
			       this,
 
			       tr("Overwrite File? -- Leaf Growth"),
 
			       tr("A file called %1 already exists."
 
				  "Do you want to overwrite it?")
 
			       .arg( fileName ),
 
			       tr("&Yes"), tr("&No"),
 
			       QString::null, 1, 1 ) ) {
 
      return snapshot();
 
      
 

	
 
    } else {
 
      
 

	
 
      // extract extension from filename
 
		QString extension = getExtension(fileName);
 
		
 
		// Save bitmaps at 1024x768
 
		Save((const char *)fileName, extension, 1024, 768);
 
      QString extension = getExtension(fileName);
 

	
 
      // Save bitmaps at 1024x768
 
      Save((const char *)fileName, extension, 1024, 768);
 
    }
 
  }
 

	
 
}
 

	
 
 
 

	
 

	
 
void Main::readPrevStateXML() {
 
  
 
void Main::readPrevStateXML()
 
{
 

	
 
  // if we have already read a file, read the next file
 
  if (!currentFile.isEmpty() && working_dir) {
 
    QString next_file;
 
    
 

	
 
    QStringList xml_files = working_dir->entryList("*.xml");
 
    QString currentFile_nopath = currentFile.section( '/', -1 );
 
    QString currentFile_path = currentFile.section( '/', 0, -2 );
 
    
 

	
 
    QList<QString>::iterator f = xml_files.find( currentFile_nopath );
 
   
 

	
 
    if (f == xml_files.end()) {
 
      return;
 
    }
 
    
 

	
 
    if (f==xml_files.begin()) {
 
      QMessageBox mb( "Read previous leaf",
 
		      "No more files",
 
		      QMessageBox::Information,
 
		      QMessageBox::Ok | QMessageBox::Default,
 
		      QMessageBox::NoButton,
 
		      QMessageBox::NoButton);
 
      mb.exec();
 
      return;
 
    }
 
    next_file = *(--f);
 
    next_file = currentFile_path+"/"+next_file;
 
    
 

	
 
    readStateXML((const char *)next_file);
 
    
 

	
 
  }
 
}
 

	
 
int Main::readStateXML(const char *filename, bool geometry, bool pars, bool simtime) {
 
 
 
int Main::readStateXML(const char *filename, bool geometry, bool pars, bool simtime)
 
{
 

	
 
  try {
 
    xmlNode *settings;
 
    mesh.XMLRead((const char *)filename, &settings, geometry, pars, simtime);
 
    #ifdef QDEBUG
 
#ifdef QDEBUG
 
    qDebug() << "Reading done."<< endl;
 
    #endif
 
#endif
 
    XMLReadSettings(settings);
 
    xmlFree(settings);
 
    Cell::SetMagnification(1);
 
    Cell::setOffset(0,0);
 
    
 

	
 
    FitLeafToCanvas();
 
    
 

	
 
    currentFile =  QString(filename);
 
	
 

	
 
    Plot();
 
    QString status_message = QString("Successfully read leaf from file %1. Time is %2 h.").arg(currentFile).arg(mesh.getTimeHours().c_str());
 
    cerr << status_message.toStdString() << endl;
 
	setCaption(caption_with_file.arg(filename));
 
    setCaption(caption_with_file.arg(filename));
 
    statusBar()->message(status_message);
 
    emit ParsChanged();
 
    #ifdef QDEBUG
 
#ifdef QDEBUG
 
    qDebug() << "Done. Returning 0." << endl;
 
    #endif
 
#endif
 
    return 0;
 
  } catch (const char *error_message) {
 
    QMessageBox mb( "Read leaf from XML file",
 
		    QString(error_message),
 
		    QMessageBox::Critical,
 
		    QMessageBox::Ok | QMessageBox::Default,
 
		    Qt::NoButton,
 
		    Qt::NoButton);
 
    mb.exec();
 
    return 1;
 
  }
 
  
 
}
 

	
 

	
 
void Main::readNextStateXML() {
 
  
 
void Main::readNextStateXML()
 
{
 

	
 
  // if we have already read a file, read the next file
 
  if (!currentFile.isEmpty() && working_dir) {
 
    QString next_file;
 
    
 

	
 
    QStringList xml_files = working_dir->entryList("*.xml");
 
    QString currentFile_nopath = currentFile.section( '/', -1 );
 
    QString currentFile_path = currentFile.section( '/', 0, -2 );
 
    
 
    
 

	
 

	
 
    QList<QString>::iterator f = xml_files.find( currentFile_nopath );
 
   
 

	
 
    if (f == xml_files.end()) {
 
      return;
 
    }
 
    
 

	
 
    ++f;
 
    if (f==xml_files.end()) {
 
      QMessageBox mb( "Read next leaf",
 
		      "No more files",
 
		      QMessageBox::Information,
 
		      QMessageBox::Ok | QMessageBox::Default,
 
		      QMessageBox::NoButton,
 
		      QMessageBox::NoButton);
 
      mb.exec();
 
      return;
 
    }
 
    next_file = *f;
 
    next_file = currentFile_path+"/"+next_file;
 

	
 
    readStateXML((const char*)next_file);
 
  }
 
  
 
  
 
}
 

	
 
void Main::readLastStateXML() {
 
  
 
void Main::readLastStateXML()
 
{
 

	
 
  // if we have already read a file, read the next file
 
  if (!currentFile.isEmpty() && working_dir) {
 
    QString next_file;
 
    
 

	
 
    QStringList xml_files = working_dir->entryList("*.xml");
 
    QString currentFile_nopath = currentFile.section( '/', -1 );
 
    QString currentFile_path = currentFile.section( '/', 0, -2 );
 
    
 
    
 

	
 

	
 
    next_file = xml_files.back();
 
    
 

	
 
    next_file = currentFile_path+"/"+next_file;
 

	
 
    readStateXML((const char*)next_file);
 
  }
 
  
 
  
 
}
 

	
 

	
 
void Main::readFirstStateXML() {
 
  
 
void Main::readFirstStateXML()
 
{
 

	
 
  // if we have already read a file, read the next file
 
  if (!currentFile.isEmpty() && working_dir) {
 
    QString next_file;
 
    
 

	
 
    QStringList xml_files = working_dir->entryList("*.xml");
 
    QString currentFile_nopath = currentFile.section( '/', -1 );
 
    QString currentFile_path = currentFile.section( '/', 0, -2 );
 
    
 
    
 

	
 

	
 
    next_file = xml_files.front();
 
    
 

	
 
    next_file = currentFile_path+"/"+next_file;
 

	
 
    readStateXML((const char*)next_file);
 
  }
 
  
 
  
 
}
 

	
 
void Main::readStateXML() {
 
void Main::readStateXML()
 
{
 

	
 
  //  extern Mesh mesh;
 

	
 
  stopSimulation();
 
  #ifdef QDEBUG
 
#ifdef QDEBUG
 
  qDebug() << "Trying to open an OptionFileDialog" << endl;
 
  #endif
 
#endif
 
  OptionFileDialog *fd = new OptionFileDialog( this, "read dialog", TRUE );
 
  fd->setMode( OptionFileDialog::ExistingFile );
 
  fd->setFilter( "XML files (*.xml)");
 
  if (working_dir) {
 
    fd->setDir(*working_dir);
 
  }
 
  QString fileName;
 
  if ( fd->exec() == QDialog::Accepted ) {
 
    
 

	
 
    fileName = fd->selectedFile();
 
    if (working_dir) {
 
      delete working_dir;
 
    }
 
    working_dir = fd->dir();
 
	
 

	
 
    if (readStateXML((const char *)fileName,fd->readGeometryP(), fd->readParametersP()) )
 
      return readStateXML(); // user can try again
 
  }
 
}
 

	
 

	
 
void Main::clear()
 
{
 
  editor->clear();
 
}
 

	
 
void Main::help()
 
{
 
  static QMessageBox* about = new QMessageBox
 
    ( "About",
 
      "<h3>Virtual Leaf</h3>"
 
      "<p>"
 
      "Leaf growth computer model <br>"
 
      "(c) 2005-2007, Roeland Merks <br>"
 
      "VIB Department Plant Systems Biology <br>"
 
	 "Ghent, Belgium <br>"
 
      "Ghent, Belgium <br>"
 
      "(c) 2008-2009, Roeland Merks <br>"
 
      "CWI/NCSB, Amsterdam, Netherlands <br>"
 
      "Pilot release for WUR/Biometris, 21-10-2009 <br>", 
 
      QMessageBox::Information, 1, 0, 0, this, 0, FALSE );
 
  about->setButtonText( 1, "Dismiss" );
 
  about->show();
 
}
 

	
 
  void Main::aboutQt()
 
  {
 
    QMessageBox::aboutQt( this, "Virtual Leaf" );
 
  }
 
void Main::aboutQt(){
 
  QMessageBox::aboutQt( this, "Virtual Leaf" );
 
}
 

	
 
  void Main::toggleShowCellCenters()
 
  {
 
    Plot();
 
  }
 
void Main::toggleShowCellCenters()
 
{
 
  Plot();
 
}
 

	
 
  void Main::toggleShowWalls()
 
  {
 
    Plot();
 
  }
 
void Main::toggleShowWalls()
 
{
 
  Plot();
 
}
 

	
 
void Main::toggleShowApoplasts()
 
{
 
    Plot();
 
  Plot();
 
}
 
  void Main::toggleShowNodes()
 
  {
 
    Plot();
 
  }
 

	
 
void Main::toggleShowNodes()
 
{
 
  Plot();
 
}
 

	
 
  void Main::toggleNodeNumbers(void) {
 
    Plot();
 
  }
 
void Main::toggleNodeNumbers(void)
 
{
 
  Plot();
 
}
 

	
 
  void Main::toggleCellNumbers(void) {
 
    Plot();
 
  }
 
void Main::toggleCellNumbers(void)
 
{
 
  Plot();
 
}
 

	
 
  void Main::toggleCellAxes(void) {
 
    Plot();
 
  }
 

	
 
  void Main::toggleCellStrain(void) {
 
    Plot();
 
  }
 
void Main::toggleCellAxes(void)
 
{
 
  Plot();
 
}
 

	
 
  void Main::toggleShowFluxes(void) {
 
    Plot();
 
  }
 
void Main::toggleCellStrain(void)
 
{
 
  Plot();
 
}
 

	
 
  void Main::toggleShowBorderCells(){
 
    Plot();
 
  }
 
void Main::toggleShowFluxes(void)
 
{
 
  Plot();
 
}
 

	
 
void Main::toggleHideCells(void) {
 
	Plot();
 
	editor->FullRedraw();
 
void Main::toggleShowBorderCells()
 
{
 
  Plot();
 
}
 
  void Main::toggleMovieFrames(){}
 

	
 
  void Main::toggleLeafBoundary(){}
 
void Main::toggleHideCells(void)
 
{
 
  Plot();
 
  editor->FullRedraw();
 
}
 

	
 
void Main::toggleMovieFrames(){}
 

	
 
void Main::toggleLeafBoundary(){}
 

	
 
void Main::toggleDynCells() {}
 

	
 
  void Main::toggleDynCells() {}
 
  
 
  void Main::startSimulation(void) {
 
    timer->start( 0 );
 
    statusBar()->message("Simulation started");
 
    running = true;
 
  }
 
void Main::startSimulation(void)
 
{
 
  timer->start( 0 );
 
  statusBar()->message("Simulation started");
 
  running = true;
 
}
 

	
 
  void Main::stopSimulation(void) {
 
    timer->stop();
 
    cerr << "Stopping simulation" << endl;
 
    statusBar()->message("Simulation paused");
 
    running = false;
 
void Main::stopSimulation(void)
 
{
 
  timer->stop();
 
  cerr << "Stopping simulation" << endl;
 
  statusBar()->message("Simulation paused");
 
  running = false;
 
}
 

	
 
void Main::togglePaused()
 
{
 
  bool s = run->isItemChecked(paused_id);
 
  if (s) {
 
    cerr << "Calling start simulation" << endl;
 
    startSimulation();
 
  } else {
 
    cerr << "Calling stop simulation" << endl;
 
    stopSimulation();
 
  }
 
}
 

	
 
  void Main::togglePaused()
 
  {
 
    bool s = run->isItemChecked(paused_id);
 
    if (s) {
 
      cerr << "Calling start simulation" << endl;
 
      startSimulation();
 
    } else {
 
      cerr << "Calling stop simulation" << endl;
 
      stopSimulation();
 
    }
 
  }
 

	
 
  void Main::setFluxArrowSize(int size) {
 
  
 
    flux_arrow_size = size/100.;
 
  }
 
void Main::setFluxArrowSize(int size)
 
{
 
  flux_arrow_size = size/100.;
 
}
 

	
 

	
 
  void Main::enlarge()
 
  {
 
    canvas.setSceneRect( QRectF( 0,0, canvas.width()*4./3., canvas.height()*4./3.) );
 
  }
 
void Main::enlarge()
 
{
 
  canvas.setSceneRect( QRectF( 0,0, canvas.width()*4./3., canvas.height()*4./3.) );
 
}
 

	
 
  void Main::shrink()
 
  {
 
    canvas.setSceneRect( QRectF( 0,0, canvas.width()*3/4, canvas.height()*3/4) );
 
  }
 
void Main::shrink()
 
{
 
  canvas.setSceneRect( QRectF( 0,0, canvas.width()*3/4, canvas.height()*3/4) );
 
}
 

	
 

	
 
  void Main::scale(double factor) {
 
    QMatrix m = editor->matrix();
 
    m.scale(factor, factor);
 
    editor->setMatrix( m );
 
  }
 
void Main::scale(double factor)
 
{
 
  QMatrix m = editor->matrix();
 
  m.scale(factor, factor);
 
  editor->setMatrix( m );
 
}
 

	
 
  void Main::zoomIn()
 
  {
 
    QMatrix m = editor->matrix();
 
    m.scale( 1.1, 1.1 );
 
    editor->setMatrix( m );
 
  }
 
void Main::zoomIn()
 
{
 
  QMatrix m = editor->matrix();
 
  m.scale( 1.1, 1.1 );
 
  editor->setMatrix( m );
 
}
 

	
 
  void Main::zoomOut()
 
  {
 
    QMatrix m = editor->matrix();
 
    m.scale( 0.9, 0.9 );
 
    editor->setMatrix( m );
 
  }
 
void Main::zoomOut()
 
{
 
  QMatrix m = editor->matrix();
 
  m.scale( 0.9, 0.9 );
 
  editor->setMatrix( m );
 
}
 

	
 

	
 
  void Main::print()
 
  {
 
    if ( !printer ) printer = new QPrinter;
 
    
 
    if ( printer->setup(this) ) {
 
    
 
      //    extern Mesh mesh;
 
      Vector bbll,bbur;
 
      mesh.BoundingBox(bbll,bbur);
 
void Main::print()
 
{
 
  if ( !printer ) printer = new QPrinter;
 

	
 
  if ( printer->setup(this) ) {
 

	
 
    //    extern Mesh mesh;
 
    Vector bbll,bbur;
 
    mesh.BoundingBox(bbll,bbur);
 

	
 
      #ifdef QDEBUG
 
      qDebug() << "bbll = " << bbll << endl;
 
      qDebug() << "bbur = " << bbur << endl;
 
      #endif
 
      double cw = (bbur.x - bbll.x);
 
      double ch = (bbur.y - bbll.y);
 
      QPainter pp(printer);
 
      QRect vp=pp.viewport();
 
      #ifdef QDEBUG
 
      qDebug() << "Paper width = " << vp.width() << " x " << vp.height() << endl;
 
      #endif
 
#ifdef QDEBUG
 
    qDebug() << "bbll = " << bbll << endl;
 
    qDebug() << "bbur = " << bbur << endl;
 
#endif
 
    double cw = (bbur.x - bbll.x);
 
    double ch = (bbur.y - bbll.y);
 
    QPainter pp(printer);
 
    QRect vp=pp.viewport();
 
#ifdef QDEBUG
 
    qDebug() << "Paper width = " << vp.width() << " x " << vp.height() << endl;
 
#endif
 

	
 
      // Note that Cell is also translated...
 
      pp.translate(-bbur.x,-bbur.y);
 
      if (cw>ch) {
 
	pp.scale(vp.width()/(2*cw*Cell::Magnification()), vp.width()/(2*cw*Cell::Magnification()));
 
      } else {
 
	pp.scale(vp.height()/(2*ch*Cell::Magnification()), vp.height()/(2*ch*Cell::Magnification()));
 
      }
 
      canvas.render(&pp, QRectF(), QRectF(0.,0.,canvas.width(),canvas.height()));
 
    // Note that Cell is also translated...
 
    pp.translate(-bbur.x,-bbur.y);
 
    if (cw>ch) {
 
      pp.scale(vp.width()/(2*cw*Cell::Magnification()), vp.width()/(2*cw*Cell::Magnification()));
 
    } else {
 
      pp.scale(vp.height()/(2*ch*Cell::Magnification()), vp.height()/(2*ch*Cell::Magnification()));
 
    }
 
    canvas.render(&pp, QRectF(), QRectF(0.,0.,canvas.width(),canvas.height()));
 
  }
 
}
 

	
 

	
 
  void Main::TimeStepWrap(void) {
 
  
 
    static int t=0;
 
    TimeStep();
 
    t++;
 
    // check number of timesteps
 
    if (t==par.nit) {
 
      emit SimulationDone();
 
    }
 
void Main::TimeStepWrap(void)
 
{
 
  static int t=0;
 
  TimeStep();
 
  t++;
 
  // check number of timesteps
 
  if (t==par.nit) {
 
    emit SimulationDone();
 
  }
 
}
 

	
 

	
 
  void Main::RestartSim(void) {
 

	
 
    stopSimulation();
 
    if ( QMessageBox::question(
 
			       this,
 
			       tr("Restart simulation?"),
 
			       tr("Restart simulation.\n"
 
				  "Are you sure?"),
 
							   QMessageBox::Yes | QMessageBox::No, QMessageBox::NoButton ) == QMessageBox::Yes ) {
 
void Main::RestartSim(void)
 
{
 

	
 
      cerr << "Restarting simulation" << endl;
 
      //    extern Mesh mesh;
 
      mesh.Clear();
 
      Init();
 
		Plot();
 
		editor->FullRedraw();
 
    } 
 
    //startSimulation();
 
  }
 
  stopSimulation();
 
  if ( QMessageBox::question(
 
			     this,
 
			     tr("Restart simulation?"),
 
			     tr("Restart simulation.\n"
 
				"Are you sure?"),
 
			     QMessageBox::Yes | QMessageBox::No, QMessageBox::NoButton ) == QMessageBox::Yes ) {
 

	
 
    cerr << "Restarting simulation" << endl;
 
    //    extern Mesh mesh;
 
    mesh.Clear();
 
    Init();
 
    Plot();
 
    editor->FullRedraw();
 
  } 
 
  //startSimulation();
 
}
 

	
 

	
 
void Main::FitCanvasToWindow(void) {
 
  
 
void Main::FitCanvasToWindow(void)
 
{
 

	
 
  double scale_factor_x = (double)editor->width()/(double)canvas.width();
 
  double scale_factor_y = (double)editor->height()/(double)canvas.height();
 
  double scale_factor = scale_factor_x > scale_factor_y ? scale_factor_x : scale_factor_y;
 
  QMatrix m = editor->matrix();
 

	
 
  #ifdef QDEBUG  
 
#ifdef QDEBUG  
 
  qDebug() << "editor->width() = " << editor->width() << endl;
 
  qDebug() << "editor->height() = " << editor->height() << endl;
 
  
 

	
 
  qDebug() << "scale_factor = " << scale_factor << endl;
 
  qDebug() << "scale_factor_x = " << scale_factor_x << endl;
 
  qDebug() << "scale_factor_y = " << scale_factor_y << endl;
 
  #endif
 
#endif
 
  m.scale( scale_factor, scale_factor );
 
  editor->setMatrix( m );
 
  editor->show();
 
}
 

	
 
  void Main::PauseIfRunning(void) {
 
    if (running) {
 
      timer->stop();
 
    }
 
void Main::PauseIfRunning(void)
 
{
 
  if (running) {
 
    timer->stop();
 
  }
 
}
 

	
 
  void Main::ContIfRunning(void) {
 
    if (running) {
 
      timer->start( 0 );
 
    }
 
void Main::ContIfRunning(void)
 
{
 
  if (running) {
 
    timer->start( 0 );
 
  }
 
}
 

	
 
void Main::FitLeafToCanvas(void) {
 
void Main::FitLeafToCanvas(void) 
 
{
 

	
 
  Vector ll,ur;
 
  mesh.BoundingBox(ll, ur);
 
  
 

	
 
  ll*=Cell::Magnification(); ur*=Cell::Magnification();
 
  
 

	
 
  // give the leaf some space
 
  Vector border = ((ur-ll)/5.);
 
  
 

	
 
  QRectF bb( ll.x - border.x, ll.y - border.y, ur.x-ll.x + 2*border.x, ur.y-ll.y + 2*border.y );
 
  
 
  
 

	
 

	
 
  // cerr << ur << ", " << ll << endl;
 
  editor->fitInView(bb, Qt::KeepAspectRatio);
 
}
 

	
 
void Main::CleanMesh(void) {
 
	vector<double> clean_chem(Cell::NChem());
 
	vector<double> clean_transporters(Cell::NChem());
 
void Main::CleanMesh(void) 
 
{
 
  vector<double> clean_chem(Cell::NChem());
 
  vector<double> clean_transporters(Cell::NChem());
 

	
 
	for (int i=0;i<Cell::NChem();i++) {
 
		clean_chem[i]=par.initval[i];
 
		clean_transporters[i]=0.;		
 
	}
 
	
 
	mesh.CleanChemicals(clean_chem);
 
	mesh.CleanTransporters(clean_transporters);
 
	
 
	mesh.setTime(0);
 
	Plot();
 
	
 
	editor->FullRedraw();
 
  for (int i=0;i<Cell::NChem();i++) {
 
    clean_chem[i]=par.initval[i];
 
    clean_transporters[i]=0.;		
 
  }
 

	
 
  mesh.CleanChemicals(clean_chem);
 
  mesh.CleanTransporters(clean_transporters);
 

	
 
  mesh.setTime(0);
 
  Plot();
 

	
 
  editor->FullRedraw();
 
}
 

	
 
void Main::CleanMeshChemicals(void) {
 
	
 
	vector<double> clean_chem(Cell::NChem());
 
void Main::CleanMeshChemicals(void) 
 
{
 

	
 
  vector<double> clean_chem(Cell::NChem());
 

	
 
	for (int i=0;i<Cell::NChem();i++) {
 
		clean_chem[i]=par.initval[i];
 
	}
 
	
 
	mesh.CleanChemicals(clean_chem);
 
	mesh.setTime(0);
 
	Plot();
 
	
 
	editor->FullRedraw();
 
  for (int i=0;i<Cell::NChem();i++) {
 
    clean_chem[i]=par.initval[i];
 
  }
 

	
 
  mesh.CleanChemicals(clean_chem);
 
  mesh.setTime(0);
 
  Plot();
 

	
 
  editor->FullRedraw();
 
}
 

	
 
void Main::CleanMeshTransporters(void) {
 
	vector<double> clean_transporters(Cell::NChem());
 
	for (int i=0;i<Cell::NChem();i++) {
 
		clean_transporters[i]=0.;
 
	}
 
	
 
	mesh.CleanTransporters(clean_transporters);
 
	
 
	mesh.setTime(0);
 
	Plot();
 
	
 
	editor->FullRedraw();
 
void Main::CleanMeshTransporters(void) 
 
{
 
  vector<double> clean_transporters(Cell::NChem());
 
  for (int i=0;i<Cell::NChem();i++) {
 
    clean_transporters[i]=0.;
 
  }
 

	
 
  mesh.CleanTransporters(clean_transporters);
 

	
 
  mesh.setTime(0);
 
  Plot();
 

	
 
  editor->FullRedraw();
 
}
 

	
 
void Main::RandomizeMesh(void) {
 
  
 
void Main::RandomizeMesh(void) 
 
{
 

	
 
  vector<double> max_chem(Cell::NChem());
 
  vector<double> max_transporters(Cell::NChem());
 
  
 

	
 
  for (int i=0;i<Cell::NChem();i++) {
 
    max_transporters[i]=0.;
 
    max_chem[i]=par.initval[i];
 
  }
 

	
 
  // Amount of PIN1 at walls
 
  max_transporters[1] = 0.01;
 
  
 

	
 
  mesh.RandomizeChemicals(max_chem, max_transporters);
 
  
 

	
 
  Plot();
 
}
 

	
 
void Main::XMLReadSettings(xmlNode *settings) {
 
  
 
void Main::XMLReadSettings(xmlNode *settings) 
 
{
 

	
 
  MainBase::XMLReadSettings(settings);
 

	
 
  view->setItemChecked(com_id, showcentersp);
 
  view->setItemChecked(mesh_id, showmeshp);
 
  view->setItemChecked(border_id, showbordercellp);
 
  view->setItemChecked(node_number_id, shownodenumbersp);
 
  view->setItemChecked(cell_number_id, showcellnumbersp);
 
  view->setItemChecked(cell_axes_id, showcellsaxesp);
 
  view->setItemChecked(cell_strain_id, showcellstrainp);
 
  view->setItemChecked(movie_frames_id, movieframesp);
 
  view->setItemChecked(only_boundary_id, showboundaryonlyp);
 
  view->setItemChecked(fluxes_id, showfluxesp);
 
  view->setItemChecked(hide_cells_id, hidecellsp);
 
  options->setItemChecked(dyn_cells_id, dynamicscellsp);
 
  view->setItemChecked( cell_walls_id, showwallsp);
 
	view->setItemChecked( apoplasts_id, showapoplastsp);
 
  view->setItemChecked( apoplasts_id, showapoplastsp);
 
}
 

	
 
xmlNode *Main::XMLSettingsTree(void) {
 
xmlNode *Main::XMLSettingsTree(void) 
 
{
 

	
 
  showcentersp = view->isItemChecked(com_id);
 
  showmeshp = view->isItemChecked(mesh_id);
 
  showbordercellp =  view->isItemChecked(border_id);
 
  shownodenumbersp =  view->isItemChecked(node_number_id);
 
  showcellnumbersp =  view->isItemChecked(cell_number_id);
 
  showcellsaxesp = view->isItemChecked( cell_axes_id );
 
  showcellstrainp = view->isItemChecked( cell_strain_id );
 
  movieframesp = view->isItemChecked(movie_frames_id);;
 
  showboundaryonlyp =  view->isItemChecked(only_boundary_id);
 
  showfluxesp = view->isItemChecked(fluxes_id);
 
  dynamicscellsp = options->isItemChecked(dyn_cells_id);
 
  showwallsp = view->isItemChecked( cell_walls_id);
 
	showapoplastsp = view->isItemChecked( apoplasts_id);
 
  showapoplastsp = view->isItemChecked( apoplasts_id);
 
  hidecellsp = view->isItemChecked( hide_cells_id);
 

	
 
  return MainBase::XMLSettingsTree();
 
}
 

	
 
/* finis */
 

	
src/canvas.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#ifndef _CANVAS_H_
 
#define _CANVAS_H_
 

	
 
#include <q3popupmenu.h>
 
#include <q3mainwindow.h>
 
#include <q3intdict.h>
 
#include <QGraphicsScene>
 
#include <QGraphicsView>
 
#include <QList>
 

	
 
#include <string>
 
#include <sstream>
 

	
 
//Added by qt3to4:
 
#include <QMouseEvent>
 
#include <vector>
 
#include "simitembase.h"
 
#include "mainbase.h"
 
#include "cellitem.h"
 
#include "infobar.h"
 

	
 
#include "nodeitem.h"
 
#include "cell.h"
 

	
 
#ifdef HAVE_QWT
 
#include "data_plot.h"
 
#endif
 

	
 
#include <libxml/xpath.h>
 
#include <libxml/xmlreader.h>
 

	
 
#if defined(Q_OS_MAC)
 
  #define PREFIX "cmd"
 
#define PREFIX "cmd"
 
#else
 
  #define PREFIX "crtl"
 
#define PREFIX "crtl"
 
#endif
 

	
 

	
 
class QFile;
 
class QDir;
 
class ModelCatalogue;
 
class InfoBar;
 

	
 
class FigureEditor : public QGraphicsView {
 
  Q_OBJECT
 

	
 
    friend class Main;
 
    public:
 
 public:
 
  FigureEditor(QGraphicsScene&, Mesh&, QWidget* parent=0, const char* name=0, Qt::WFlags f=0);
 
  void clear();
 
  void Save(const char *fname, const char *format, int sizex=640, int sizey=480);
 
  void FullRedraw(void);
 

	
 
protected:
 
 protected:
 
  void mousePressEvent(QMouseEvent*);
 
  void mouseMoveEvent(QMouseEvent*);
 
  void mouseReleaseEvent(QMouseEvent*);
 
  void wheelEvent(QWheelEvent *event);
 
  void scaleView(qreal scaleFactor);
 

	
 
  vector <CellItem *> getIntersectedCells(void);
 
  void insertNode(QPointF p);
 
  NodeItem *selectedNodeItem(QList<QGraphicsItem *> l) const;  
 

	
 
 signals:
 
  void status(const QString&);
 
  void MousePressed(void);
 
  void MouseReleased(void);
 
 protected:
 
  Mesh &mesh;
 

	
 
 private:
 
  //NodeItem* moving;
 
  SimItemBase *moving;
 
  QPointF moving_start;
 
    
 

	
 
  QGraphicsLineItem *intersection_line;
 
  bool rotation_mode;
 
  bool insert_mode;
 
  double rot_angle;
 
};
 

	
 
class Main : public Q3MainWindow, public MainBase {
 
  Q_OBJECT
 
	friend class ModelCatalogue; // needs to populate menu item models
 
    public:
 
    friend class ModelCatalogue; // needs to populate menu item models
 
 public:
 
  Main(QGraphicsScene&, Mesh&, QWidget* parent=0, const char* name=0, Qt::WFlags f=0);
 
  ~Main();
 
  virtual bool ShowCentersP(void) {return view->isItemChecked(com_id);}
 
  virtual bool ShowMeshP(void) {return view->isItemChecked(mesh_id);}
 
  virtual bool ShowBorderCellsP(void) {return view->isItemChecked(border_id);}
 
  virtual bool PausedP(void) {return run->isItemChecked(paused_id);}
 
  virtual bool ShowNodeNumbersP(void) {return view->isItemChecked(node_number_id);}
 
  virtual bool ShowCellNumbersP(void) {return view->isItemChecked(cell_number_id);}
 
  virtual bool ShowCellAxesP(void) {return view->isItemChecked(cell_axes_id);}
 
  virtual bool ShowCellStrainP(void) {return view->isItemChecked(cell_strain_id);}
 
  virtual bool MovieFramesP(void) {return view->isItemChecked(movie_frames_id);}
 
  virtual bool ShowBoundaryOnlyP(void) {return view->isItemChecked(only_boundary_id);}
 
  virtual bool ShowWallsP(void) {return view->isItemChecked(cell_walls_id);}
 
	virtual bool ShowApoplastsP(void) { return view->isItemChecked(apoplasts_id);}
 
  virtual bool ShowApoplastsP(void) { return view->isItemChecked(apoplasts_id);}
 
  virtual bool ShowFluxesP(void) { return view->isItemChecked(fluxes_id); }
 
  virtual bool DynamicCellsP(void) { return options->isItemChecked(dyn_cells_id); }
 
  virtual bool RotationModeP(void) { return options->isItemChecked(rotation_mode_id); }
 
  virtual bool InsertModeP(void) { return options->isItemChecked(insert_mode_id); }
 
  virtual bool ShowToolTipsP(void) { return helpmenu->isItemChecked(tooltips_id); }
 
  virtual bool HideCellsP(void) { return view->isItemChecked(hide_cells_id); }
 
  void scale(double factor); 
 
  virtual double getFluxArrowsize(void) {
 
  virtual double getFluxArrowsize(void)
 
  {
 
    return flux_arrow_size;
 
  }
 
    
 

	
 
  void FitCanvasToWindow();
 
  void FitLeafToCanvas(void);
 

	
 

	
 
  public slots:
 

	
 
  void help();
 
  void TimeStepWrap();
 
  void togglePaused();
 
  void setFluxArrowSize(int size);
 
  void RestartSim(void);
 
  void toggleShowCellCenters(void);
 
  void toggleShowNodes(void);
 
  void toggleShowBorderCells(void);
 
  void toggleShowFluxes(void);
 
  void toggleNodeNumbers(void);
 
  void toggleCellNumbers(void);
 
  void toggleCellAxes(void);
 
  void toggleCellStrain(void);
 
  void toggleShowWalls(void);
 
  void toggleShowApoplasts(void);
 
  void toggleDynCells(void);
 
  void toggleMovieFrames(void);
 
  void toggleLeafBoundary(void);
 
  void toggleHideCells(void);
 
  void print();
 
  void startSimulation(void);
 
  void stopSimulation(void);
 
  void RefreshInfoBar(void);
 

	
 
  void EnterRotationMode(void) {
 
  void EnterRotationMode(void)
 
  {
 

	
 
    UserMessage("Rotation mode. Click mouse to exit.");
 
    if (editor) {
 
      editor->rot_angle = 0. ; 
 

	
 
      // Exit rotation mode if mouse is clicked
 
      connect(editor, SIGNAL(MousePressed()), this, SLOT(ExitRotationMode()));
 
    }
 
  
 

	
 
  }
 
  void ExitRotationMode(void) { 
 
  void ExitRotationMode(void)
 
  { 
 
    UserMessage("Exited rotation mode.",2000);
 

	
 
    options->setItemChecked(rotation_mode_id, false); 
 
    if (editor)
 
      disconnect(editor, SIGNAL(MousePressed()), this, SLOT(ExitRotationMode()));
 
  }
 

	
 
  virtual void UserMessage(QString message, int timeout=0);
 
  void Refresh(void) { Plot(); }
 
  void PauseIfRunning(void);
 
  void ContIfRunning(void);
 
  virtual void XMLReadSettings(xmlNode *settings);
 
   
 

	
 
  private slots:
 
  void aboutQt();
 
  void newView();
 
  void EditParameters();
 
  void readStateXML();
 
  int readStateXML(const char *filename, bool geometry = true, bool pars=true, bool simtime = true);
 
  void readNextStateXML();
 
  void readPrevStateXML();
 
  void readFirstStateXML();
 
  void readLastStateXML();
 
  void saveStateXML();
 
  void snapshot();
 
  void savePars();
 
  void readPars();
 
  void clear();
 
  void init();
 
  virtual void CutSAM() { MainBase::CutSAM(); Refresh();}
 

	
 
  void enlarge();
 
  void shrink();
 
  void zoomIn();
 
  void zoomOut();
 
	
 

	
 
  void CleanMesh();
 
	void CleanMeshChemicals(void);
 
	void CleanMeshTransporters(void);
 
	
 
  void CleanMeshChemicals(void);
 
  void CleanMeshTransporters(void);
 

	
 
  void RandomizeMesh();
 

	
 
 signals:
 
  void SimulationDone(void);
 
  void ParsChanged(void);
 
  
 

	
 
 protected:
 
  Mesh &mesh;
 
  
 

	
 
 private:
 
  NodeSet *node_set;
 
  FigureEditor *editor;
 
  Q3PopupMenu* options;
 
  Q3PopupMenu *view;
 
  Q3PopupMenu *run;
 
	QMenu *modelmenu;
 
  QMenu *modelmenu;
 
  Q3PopupMenu *helpmenu;
 

	
 
  QPrinter* printer;
 
  const QDir *working_dir;
 
  QString currentFile;
 
  //  toggle item states 
 
  int dbf_id; // options->Double Buffer
 
  int com_id; // view->Show centers
 
  int mesh_id; // view->Show mesh
 
  int node_number_id; // view->Show Node numbers
 
  int cell_number_id; // view->Show Cell numbers
 
  int border_id; // view->Show border cells
 
  int paused_id; // run->Simulation paused
 
  int cell_axes_id; // view->Show cell axes
 
  int cell_strain_id; // view->Show cell strain
 
  int only_boundary_id; // view ->Show only leaf boundary
 
  int cell_walls_id; // view -> Show transporters
 
	int apoplasts_id; // view -> Show apoplasts
 
  int apoplasts_id; // view -> Show apoplasts
 
  int tooltips_id; // help -> Show Cell Info
 
  int hide_cells_id; // view->Hide Cells
 
  double flux_arrow_size;
 
  int movie_frames_id;
 
  int fluxes_id;
 
  int dyn_cells_id;
 
  int rotation_mode_id;
 
  int insert_mode_id;
 
  QTimer *timer;
 
  QFile *gifanim;
 
  bool running;
 
  virtual xmlNode *XMLSettingsTree(void);
 
  static const QString caption;
 
  static const QString caption_with_file;
 
	InfoBar *infobar;
 

	
 
  InfoBar *infobar;
 
};
 

	
 

	
 
#endif
 

	
 
#endif
 
/* finis*/
src/cell.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <QDebug>
 

	
 
#include <string>
 
#include "cell.h"
 
#include "node.h"
 
#include "mesh.h"
 
#include "tiny.h"
 
#include "nodeset.h"
 
#include "cellitem.h"
 
#include "nodeitem.h"
 
#include "qcanvasarrow.h"
 
#include "parameter.h"
 

	
 

	
 
static const std::string _module_id("$Id$");
 

	
 
extern Parameter par;
 

	
 
double Cell::factor=1.;
 
double Cell::offset[3]={0,0,0};
 

	
 
Cell::Cell(void) : CellBase() {
 

	
 
	m=0;
 

	
 
Cell::Cell(void) : CellBase()
 
{
 
  m=0;
 
}
 

	
 
Cell::Cell(double x, double y, double z) : CellBase(x,y,z) {
 

	
 
	m=0;
 
	
 
Cell::Cell(double x, double y, double z) : CellBase(x,y,z)
 
{
 
  m=0;
 
}
 

	
 
Cell::Cell(const Cell &src) :  CellBase(src) {
 
	
 
	m=src.m;
 
Cell::Cell(const Cell &src) :  CellBase(src)
 
{
 
  m=src.m;
 
}
 

	
 
bool Cell::Cmp(Cell *c) const { return this->Index() < c->Index(); }
 
bool Cell::Eq(Cell *c) const { return this->Index() == c->Index(); }
 

	
 
Cell Cell::operator=(const Cell &src) {
 
	CellBase::operator=(src);
 
	m=src.m;
 
	return *this;
 
Cell Cell::operator=(const Cell &src) 
 
{
 
  CellBase::operator=(src);
 
  m=src.m;
 
  return *this;
 
}
 
//Cell(void) : CellBase() {}
 

	
 
void Cell::DivideOverAxis(Vector axis) {
 
	
 
	// Build a wall
 
	// ->  find the position of the wall
 
	
 
	// better look for intersection with a simple line intersection algorithm as below?
 
	// this leads to some exceptions: e.g. dividing a horizontal rectangle.
 
	// leaving it like this for the time being
 
	
 
	if (dead) return;
 
	
 
	Vector centroid=Centroid();
 
	double prev_cross_z=(axis * (centroid - *(nodes.back()) ) ).z ;
 
		
 
	ItList new_node_locations;
 
	
 
	for (list<Node *>::iterator i=nodes.begin();
 
		 i!=nodes.end();
 
		 i++) {
 
		
 
		// cross product to detect position of division
 
		Vector cross = axis * (centroid - *(*i));
 
		
 
		if (cross.z * prev_cross_z < 0 ) {
 
			
 
			new_node_locations.push_back(i);
 
			
 
		}		
 
		prev_cross_z=cross.z;
 
	}
 
	
 
	DivideWalls(new_node_locations, centroid, centroid+axis);
 
	
 
void Cell::DivideOverAxis(Vector axis) 
 
{
 
  // Build a wall
 
  // ->  find the position of the wall
 

	
 
  // better look for intersection with a simple line intersection algorithm as below?
 
  // this leads to some exceptions: e.g. dividing a horizontal rectangle.
 
  // leaving it like this for the time being
 

	
 
  if (dead) return;
 

	
 
  Vector centroid=Centroid();
 
  double prev_cross_z=(axis * (centroid - *(nodes.back()) ) ).z ;
 

	
 
  ItList new_node_locations;
 

	
 
  for (list<Node *>::iterator i=nodes.begin();
 
       i!=nodes.end();
 
       i++) {
 

	
 
    // cross product to detect position of division
 
    Vector cross = axis * (centroid - *(*i));
 

	
 
    if (cross.z * prev_cross_z < 0 ) {
 

	
 
      new_node_locations.push_back(i);
 

	
 
    }		
 
    prev_cross_z=cross.z;
 
  }
 

	
 
  DivideWalls(new_node_locations, centroid, centroid+axis);
 
}
 
double Cell::MeanArea(void) {
 
	return m->MeanArea();
 

	
 
double Cell::MeanArea(void)
 
{
 
  return m->MeanArea();
 
}
 

	
 

	
 
void Cell::Apoptose(void) {
 
	
 
	// First kill walls
 
        #ifdef QDEBUG
 
        qDebug() << "This is cell " << Index() << endl;
 
	qDebug() << "Number of walls: " << walls.size() << endl;
 
	#endif
 
	for (list<Wall *>::iterator w=walls.begin(); w!=walls.end(); w++) {
 
             #ifdef QDEBUG
 
	     qDebug() << "Before apoptosis, wall " << (*w)->Index() << " says: c1 = "
 
		      << (*w)->c1->Index() << ", c2 = " << (*w)->c2->Index() << endl;
 
             #endif
 
	}
 
	for (list<Wall *>::iterator w=walls.begin();
 
		 w!=walls.end();
 
		 w++) {
 
		
 
		bool illegal_flag = false;
 
		if ((*w)->c1 == (*w)->c2 ) 
 
			illegal_flag=true;
 
		if ((*w)->c1 == this) {
 
			
 
			// invert wall?
 
			(*w)->c1 = (*w)->c2;      
 
			(*w)->c2 = m->boundary_polygon;
 
			
 
			Node *n1 = (*w)->n1;
 
			(*w)->n1 = (*w)->n2;
 
			(*w)->n2 = n1;
 
			
 
		} else {
 
			(*w)->c2 = m->boundary_polygon;
 
		}
 
		
 
		#ifdef QDEBUG
 
		if (illegal_flag && (*w)->c1==(*w)->c2) {
 
		  qDebug() << "I created an illegal wall." << endl;
 
		}
 
		#endif
 
void Cell::Apoptose(void)
 
{
 
  // First kill walls
 
#ifdef QDEBUG
 
  qDebug() << "This is cell " << Index() << endl;
 
  qDebug() << "Number of walls: " << walls.size() << endl;
 
#endif
 
  for (list<Wall *>::iterator w=walls.begin(); w!=walls.end(); w++) {
 
#ifdef QDEBUG
 
    qDebug() << "Before apoptosis, wall " << (*w)->Index() << " says: c1 = "
 
	     << (*w)->c1->Index() << ", c2 = " << (*w)->c2->Index() << endl;
 
#endif
 
  }
 
  for (list<Wall *>::iterator w=walls.begin();
 
       w!=walls.end();
 
       w++) {
 

	
 
    bool illegal_flag = false;
 
    if ((*w)->c1 == (*w)->c2 ) 
 
      illegal_flag=true;
 
    if ((*w)->c1 == this) {
 

	
 
		if ( ((*w)->N1()->DeadP() || (*w)->N2()->DeadP()) ||
 
			((*w)->C1() == (*w)->C2() ) ){
 
			// kill wall
 
		        #ifdef QDEBUG
 
		        qDebug() << "Killing wall." << endl;
 
			#endif
 
			(*w)->Kill();
 
      // invert wall?
 
      (*w)->c1 = (*w)->c2;      
 
      (*w)->c2 = m->boundary_polygon;
 

	
 
      Node *n1 = (*w)->n1;
 
      (*w)->n1 = (*w)->n2;
 
      (*w)->n2 = n1;
 

	
 
    } else {
 
      (*w)->c2 = m->boundary_polygon;
 
    }
 

	
 
#ifdef QDEBUG
 
    if (illegal_flag && (*w)->c1==(*w)->c2) {
 
      qDebug() << "I created an illegal wall." << endl;
 
    }
 
#endif
 

	
 
    if ( ((*w)->N1()->DeadP() || (*w)->N2()->DeadP()) ||
 
	 ((*w)->C1() == (*w)->C2() ) ){
 
      // kill wall
 
#ifdef QDEBUG
 
      qDebug() << "Killing wall." << endl;
 
#endif
 
      (*w)->Kill();
 

	
 
			#ifdef QDEBUG
 
			if ((*w)) {
 
			  qDebug() << "Wall " << (*w)->Index() << " says: c1 = " 
 
				   << (*w)->c1->Index() << ", c2 = " << (*w)->c2->Index() << endl;
 
			}
 
			#endif
 
			(*w)=0;
 
		} else {
 
		        #ifdef QDEBUG
 
		        qDebug() << "Not killing wall." << endl;
 
			qDebug() << "Wall " << (*w)->Index() << " says: c1 = " 
 
				 << (*w)->c1->Index() << ", c2 = " << (*w)->c2->Index() << endl;
 
                        #endif
 
		}
 
		
 
	}
 
	walls.remove(0);
 
	
 
	// Unregister me from my nodes, and delete the node if it no longer belongs to any cells
 
	list<Node *> superfluous_nodes;
 
	for (list<Node *>::iterator n=nodes.begin();
 
		 n!=nodes.end();
 
		 n++) {
 
		
 
		Node &no(*(*n));
 
		// locate myself in the node's owner list
 
		list<Neighbor>::iterator cellpos;
 
		bool cell_found=false;
 
		for (list<Neighbor>::iterator nb=no.owners.begin();
 
			 nb!=no.owners.end();
 
			 nb++) {
 
			if (nb->cell == this) {
 
				cellpos = nb;
 
				cell_found = true;
 
				break;
 
			}
 
		}
 
		
 
		if (!cell_found) {
 
			// I think this cannot happen; but if I am wrong, unpredictable things would happen. So throw an exception.
 
			throw ("Cell not found in CellBase::Apoptose()\n\rPlease correct the code to handle this situation.");
 
		}
 
		
 
		Neighbor tmp = *cellpos;
 
		no.owners.erase(cellpos);
 
		
 
		// if node has no owners left, or only has a connection to special cell -1 (outside world), mark it as dead.
 
		
 
		if (no.owners.size()==0 || (no.owners.size()==1 && no.owners.front().cell->BoundaryPolP()) ) {
 
			no.MarkDead();
 
		} else {
 
			// register node with outside world
 
			if (find_if( no.owners.begin(), no.owners.end(), 
 
				     bind2nd ( mem_fun_ref(&Neighbor::CellEquals), m->boundary_polygon->Index() ) ) == no.owners.end() ) {
 
				
 
				tmp.cell = m->boundary_polygon;
 
				no.owners.push_back(tmp);
 
			}
 
		}
 
	}
 
	
 
	
 
	
 
	// mark cell as dead
 
	MarkDead();
 
#ifdef QDEBUG
 
      if ((*w)) {
 
	qDebug() << "Wall " << (*w)->Index() << " says: c1 = " 
 
		 << (*w)->c1->Index() << ", c2 = " << (*w)->c2->Index() << endl;
 
      }
 
#endif
 
      (*w)=0;
 
    } else {
 
#ifdef QDEBUG
 
      qDebug() << "Not killing wall." << endl;
 
      qDebug() << "Wall " << (*w)->Index() << " says: c1 = " 
 
	       << (*w)->c1->Index() << ", c2 = " << (*w)->c2->Index() << endl;
 
#endif
 
    }
 
  }
 
  walls.remove(0);
 

	
 
  // Unregister me from my nodes, and delete the node if it no longer belongs to any cells
 
  list<Node *> superfluous_nodes;
 
  for (list<Node *>::iterator n=nodes.begin();
 
       n!=nodes.end();
 
       n++) {
 

	
 
    Node &no(*(*n));
 
    // locate myself in the node's owner list
 
    list<Neighbor>::iterator cellpos;
 
    bool cell_found=false;
 
    for (list<Neighbor>::iterator nb=no.owners.begin();
 
	 nb!=no.owners.end();
 
	 nb++) {
 
      if (nb->cell == this) {
 
	cellpos = nb;
 
	cell_found = true;
 
	break;
 
      }
 
    }
 

	
 
    if (!cell_found) {
 
      // I think this cannot happen; but if I am wrong, unpredictable things would happen. So throw an exception.
 
      throw ("Cell not found in CellBase::Apoptose()\n\rPlease correct the code to handle this situation.");
 
    }
 

	
 
    Neighbor tmp = *cellpos;
 
    no.owners.erase(cellpos);
 

	
 
    // if node has no owners left, or only has a connection to special cell -1 (outside world), mark it as dead.
 

	
 
    if (no.owners.size()==0 || (no.owners.size()==1 && no.owners.front().cell->BoundaryPolP()) ) {
 
      no.MarkDead();
 
    } else {
 
      // register node with outside world
 
      if (find_if( no.owners.begin(), no.owners.end(), 
 
		   bind2nd ( mem_fun_ref(&Neighbor::CellEquals), m->boundary_polygon->Index() ) ) == no.owners.end() ) {
 

	
 
	tmp.cell = m->boundary_polygon;
 
	no.owners.push_back(tmp);
 
      }
 
    }
 
  }
 

	
 
  // mark cell as dead
 
  MarkDead();
 
}
 

	
 
void Cell::ConstructConnections(void) {
 
	
 
    // Tie up the nodes of this cell, assuming they are correctly ordered
 
	
 
    //cerr << "Constructing connections of cell " << index << endl;
 
	
 
    for (list<Node *>::iterator i=nodes.begin();
 
		 i!=nodes.end();
 
		 i++) {
 
		
 
		//cerr << "Connecting node " << *i << endl;
 
		//cerr << "Node " << *i << endl << " = " << *(*i) << endl;
 
		// 1. Tidy up existing connections (which are part of this cell)
 
		if ((*i)->owners.size()>0) {
 
			list<Neighbor>::iterator neighb_with_this_cell=
 
			// remove myself from the neighbor list of the node
 
			find_if((*i)->owners.begin(),
 
					(*i)->owners.end(),
 
				bind2nd(mem_fun_ref( &Neighbor::CellEquals ),this->Index() )  );
 
			if (neighb_with_this_cell!=(*i)->owners.end()) 
 
				(*i)->owners.erase(neighb_with_this_cell);
 
		}
 
		
 
		Node *previous;
 
		if (i!=nodes.begin()) {
 
			list<Node *>::iterator previous_iterator=i;
 
			previous_iterator--;
 
			previous=*previous_iterator;
 
		} else {
 
			previous=nodes.back();
 
		}
 
		
 
		Node *next;
 
		list<Node *>::iterator next_iterator=i;
 
		next_iterator++;
 
		if (next_iterator==nodes.end()) {
 
			next=nodes.front();
 
		} else {
 
			next=*next_iterator;
 
		}
 
		
 
		//cerr << "[" << *i << "]";
 
		//if (*i==10 || *i==11) {
 
		//cerr << "previous = " << previous << ", next = " << next << endl;
 
		//}
 
		//if (*i!=10 && *i!=11)
 
		//cerr << "Node " << *i << endl << " = " << *(*i) << endl;
 
		(*i)->owners.push_back( Neighbor( this, previous, next ) );
 
		// if (*i==50 || *i==51) {
 
		//cerr << "Node " << *i << ".size() = " << (*i)->owners.size() << endl;
 
		// }
 
void Cell::ConstructConnections(void)
 
{
 
  // Tie up the nodes of this cell, assuming they are correctly ordered
 

	
 
  //cerr << "Constructing connections of cell " << index << endl;
 

	
 
  for (list<Node *>::iterator i=nodes.begin();
 
       i!=nodes.end();
 
       i++) {
 

	
 
    //cerr << "Connecting node " << *i << endl;
 
    //cerr << "Node " << *i << endl << " = " << *(*i) << endl;
 
    // 1. Tidy up existing connections (which are part of this cell)
 
    if ((*i)->owners.size()>0) {
 
      list<Neighbor>::iterator neighb_with_this_cell=
 
	// remove myself from the neighbor list of the node
 
	find_if((*i)->owners.begin(),
 
		(*i)->owners.end(),
 
		bind2nd(mem_fun_ref( &Neighbor::CellEquals ),this->Index() )  );
 
      if (neighb_with_this_cell!=(*i)->owners.end()) 
 
	(*i)->owners.erase(neighb_with_this_cell);
 
    }
 

	
 
    Node *previous;
 
    if (i!=nodes.begin()) {
 
      list<Node *>::iterator previous_iterator=i;
 
      previous_iterator--;
 
      previous=*previous_iterator;
 
    } else {
 
      previous=nodes.back();
 
    }
 

	
 
    Node *next;
 
    list<Node *>::iterator next_iterator=i;
 
    next_iterator++;
 
    if (next_iterator==nodes.end()) {
 
      next=nodes.front();
 
    } else {
 
      next=*next_iterator;
 
    }
 
    (*i)->owners.push_back( Neighbor( this, previous, next ) );
 
  }
 
}
 

	
 
bool Cell::DivideOverGivenLine(const Vector v1, const Vector v2, bool fix_cellwall, NodeSet *node_set )
 
{
 
  if (dead) return false;
 

	
 
  // check each edge for intersection with the line
 
  ItList new_node_locations;
 

	
 
#ifdef QDEBUG
 
  qDebug() << "Cell " << Index() << " is doing DivideOverGivenLine" << endl;
 
#endif
 
  for (list<Node *>::iterator i=nodes.begin();
 
       i!=nodes.end();
 
       i++) {
 

	
 
    Vector v3 = *(*i);
 
    list<Node *>::iterator nb=i;
 
    nb++;
 
    if (nb == nodes.end()) {
 
      nb = nodes.begin();
 
    }
 
    Vector v4 = *(*nb);
 

	
 
    double denominator = 
 
      (v4.y - v3.y)*(v2.x - v1.x) - (v4.x - v3.x)*(v2.y - v1.y);
 

	
 
    double ua = 
 
      ((v4.x - v3.x)*(v1.y - v3.y) - (v4.y - v3.y)*(v1.x -v3.x))/denominator;
 
    double ub = 
 
      ((v2.x - v1.x)*(v1.y-v3.y) - (v2.y- v1.y)*(v1.x - v3.x))/denominator;
 

	
 

	
 
/*! \brief Divide the cell over the line v1-v2.
 
 
 
 \param v1: First vertex of line.
 
 \param v2: Second vertex of line.
 
 \param fixed_wall: If true: wall will be set to "fixed" (i.e. not motile)
 
 \return: true if the cell divided, false if not (i.e. no intersection between v1 and v2, and the cell)
 
 */
 
bool Cell::DivideOverGivenLine(const Vector v1, const Vector v2, bool fix_cellwall, NodeSet *node_set ) {
 
	
 
	if (dead) return false;
 
	
 
	
 
	
 
	// check each edge for intersection with the line
 
	ItList new_node_locations;
 
	
 
	#ifdef QDEBUG
 
	qDebug() << "Cell " << Index() << " is doing DivideOverGivenLine" << endl;
 
	#endif
 
	for (list<Node *>::iterator i=nodes.begin();
 
		 i!=nodes.end();
 
		 i++) {
 
		
 
		Vector v3 = *(*i);
 
		list<Node *>::iterator nb=i;
 
		nb++;
 
		if (nb == nodes.end()) {
 
			nb = nodes.begin();
 
		}
 
		Vector v4 = *(*nb);
 
		
 
		double denominator = 
 
		(v4.y - v3.y)*(v2.x - v1.x) - (v4.x - v3.x)*(v2.y - v1.y);
 
		
 
		double ua = 
 
		((v4.x - v3.x)*(v1.y - v3.y) - (v4.y - v3.y)*(v1.x -v3.x))/denominator;
 
		double ub = 
 
		((v2.x - v1.x)*(v1.y-v3.y) - (v2.y- v1.y)*(v1.x - v3.x))/denominator;
 
		
 
		
 
		//cerr << "Edge " << *i << " to " << *nb << ": ua = " << ua << ", ub = " << ub << ":  ";
 
		// this construction with "TINY" should simulate open/closed interval <0,1]
 
		if ( ( TINY < ua && ua < 1.+TINY ) && ( TINY < ub && ub < 1.+TINY ) ) {
 
			// yes, intersection detected. Push the location to the list of iterators
 
			new_node_locations.push_back(nb);
 
			
 
		} 
 
	}
 
	
 
        #ifdef QDEBUG
 
	if (new_node_locations.size()<2) { 
 
	  qDebug() << "Line does not intersect with two edges of Cell " << Index() << endl;
 
	  qDebug() << "new_node_locations.size() = " << new_node_locations.size() << endl;
 
	  return false;
 
	}
 
	
 
	ItList::iterator i = new_node_locations.begin();
 
	list< Node *>::iterator j;
 
	qDebug() << "-------------------------------" << endl;
 
	qDebug() << "Location of new nodes: " << (**i)->Index() << " and ";
 
    //cerr << "Edge " << *i << " to " << *nb << ": ua = " << ua << ", ub = " << ub << ":  ";
 
    // this construction with "TINY" should simulate open/closed interval <0,1]
 
    if ( ( TINY < ua && ua < 1.+TINY ) && ( TINY < ub && ub < 1.+TINY ) ) {
 
      // yes, intersection detected. Push the location to the list of iterators
 
      new_node_locations.push_back(nb);
 

	
 
    } 
 
}
 

	
 
#ifdef QDEBUG
 
  if (new_node_locations.size()<2) { 
 
    qDebug() << "Line does not intersect with two edges of Cell " << Index() << endl;
 
    qDebug() << "new_node_locations.size() = " << new_node_locations.size() << endl;
 
    return false;
 
  }
 

	
 
	++i;
 
	j = *i; 
 
	if (j==nodes.begin()) j=nodes.end(); j--;
 
	
 
	qDebug() << (*j)->Index() << endl;
 
	qDebug() << "-------------------------------" << endl;
 
    
 
	if ( **new_node_locations.begin() == *j ) {
 
	  qDebug() << "Rejecting proposed division (cutting off zero area)." << endl;
 
		return false;
 
	}
 
	#endif
 
ItList::iterator i = new_node_locations.begin();
 
list< Node *>::iterator j;
 
qDebug() << "-------------------------------" << endl;
 
qDebug() << "Location of new nodes: " << (**i)->Index() << " and ";
 

	
 
++i;
 
j = *i; 
 
if (j==nodes.begin()) j=nodes.end(); j--;
 

	
 
	DivideWalls(new_node_locations, v1, v2, fix_cellwall, node_set);
 
	
 
	return true;
 
	
 
qDebug() << (*j)->Index() << endl;
 
qDebug() << "-------------------------------" << endl;
 

	
 
if ( **new_node_locations.begin() == *j ) {
 
  qDebug() << "Rejecting proposed division (cutting off zero area)." << endl;
 
  return false;
 
 }
 
#endif
 

	
 
DivideWalls(new_node_locations, v1, v2, fix_cellwall, node_set);
 

	
 
return true;
 
}
 

	
 
// Core division procedure
 
void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vector to, bool fix_cellwall, NodeSet *node_set) {
 
	
 
	if (dead) return;
 
	
 
	bool boundary_touched_flag=false;
 
	
 
	// Step 0: keep some data about the parent before dividing
 
	
 
	ParentInfo parent_info;
 
	parent_info.polarization = ReduceCellAndWalls<Vector>( PINdir );
 
	parent_info.polarization.Normalise();
 
	parent_info.PINmembrane = SumTransporters(1);
 
	parent_info.PINendosome = Chemical(1);
 
	
 
	//cerr << "Parent polarization before division: " << parent_info.polarization << endl;
 
	
 
	// Step 1: create a daughter cell
 
	Cell *daughter=m->AddCell(new Cell());
 
    
 
	// Step 2: Copy the basics of parent cell to daughter
 
	for (int i=0;i<NChem();i++) {
 
		daughter->chem[i]=chem[i];
 
	}
 
	
 
	daughter->cell_type = cell_type;
 
	
 
	for (int i=0;i<NChem();i++) {
 
		daughter->new_chem[i]=new_chem[i];
 
	}
 
	
 
	
 
	daughter->boundary=boundary;
 
	daughter->m=m;
 
	
 
	daughter->target_area=target_area/2.;
 
	
 
	target_area/=2;
 
	daughter->cellvec=cellvec;
 
	
 
	
 
	// Division currently only works for convex cells: i.e. if the division line
 
	// intersects the cells at two points only.
 
	if (new_node_locations.size()!=2) {
 
		
 
		// Note: if you would add the possibility of dividing non-convex
 
		// cells, remember to update the code below. There are some
 
		// fixed-size arrays over there!
 
		
 
		cerr << "Warning in Cell::Division: division of non-convex cells not fully implemented" << endl;
 
		
 
		// Reject the daughter cell and decrement the amount of cells
 
		// again. We can do this here because it is the last cell added.
 
		// Never, ever try to fully erase a cell elsewhere, because we
 
		// make heavy use of cell indices in this project; if you erase a
 
		// Cell somewhere in the middle of Mesh::Cells the indices will
 
		// get totally messed up...! (e.g. the indices used in Nodes::cells)
 
		
 
		#ifdef QDEBUG
 
		qDebug() << "new_node_locations.size() = " << new_node_locations.size() <<endl;
 
		qDebug() << "daughter->index = " << daughter->index << endl;
 
		qDebug() << "cells.size() = " << m->cells.size() << endl;
 
		#endif
 
void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vector to, bool fix_cellwall, NodeSet *node_set)
 
{
 

	
 
  if (dead) return;
 

	
 
  bool boundary_touched_flag=false;
 

	
 
  // Step 0: keep some data about the parent before dividing
 

	
 
  ParentInfo parent_info;
 
  parent_info.polarization = ReduceCellAndWalls<Vector>( PINdir );
 
  parent_info.polarization.Normalise();
 
  parent_info.PINmembrane = SumTransporters(1);
 
  parent_info.PINendosome = Chemical(1);
 

	
 
  //cerr << "Parent polarization before division: " << parent_info.polarization << endl;
 

	
 
  // Step 1: create a daughter cell
 
  Cell *daughter=m->AddCell(new Cell());
 

	
 
  // Step 2: Copy the basics of parent cell to daughter
 
  for (int i=0;i<NChem();i++) {
 
    daughter->chem[i]=chem[i];
 
  }
 

	
 
  daughter->cell_type = cell_type;
 

	
 
  for (int i=0;i<NChem();i++) {
 
    daughter->new_chem[i]=new_chem[i];
 
  }
 

	
 
  daughter->boundary=boundary;
 
  daughter->m=m;
 

	
 
  daughter->target_area=target_area/2.;
 

	
 
  target_area/=2;
 
  daughter->cellvec=cellvec;
 

	
 
  // Division currently only works for convex cells: i.e. if the division line
 
  // intersects the cells at two points only.
 
  if (new_node_locations.size()!=2) {
 

	
 
    // Note: if you would add the possibility of dividing non-convex
 
    // cells, remember to update the code below. There are some
 
    // fixed-size arrays over there!
 

	
 
    cerr << "Warning in Cell::Division: division of non-convex cells not fully implemented" << endl;
 

	
 
    // Reject the daughter cell and decrement the amount of cells
 
    // again. We can do this here because it is the last cell added.
 
    // Never, ever try to fully erase a cell elsewhere, because we
 
    // make heavy use of cell indices in this project; if you erase a
 
    // Cell somewhere in the middle of Mesh::Cells the indices will
 
    // get totally messed up...! (e.g. the indices used in Nodes::cells)
 

	
 
#ifdef QDEBUG
 
    qDebug() << "new_node_locations.size() = " << new_node_locations.size() <<endl;
 
    qDebug() << "daughter->index = " << daughter->index << endl;
 
    qDebug() << "cells.size() = " << m->cells.size() << endl;
 
#endif
 

	
 
		m->cells.pop_back();
 
		Cell::NCells()--;
 
		m->shuffled_cells.pop_back();
 
		return;
 
	}
 
	
 
	
 
	// We can be sure we only need two positions here because divisions
 
	// of non-convex cells are rejected above.
 
	Vector new_node[2];
 
	Node *new_node_ind[2];
 
	
 
	int new_node_flag[2];
 
	Edge div_edges[2];
 
	
 
	int nnc=0;
 
	
 
	Wall *div_wall[4];
 
	double orig_length[2];
 
	for (int i=0;i<4;i++) { div_wall[i]=0; orig_length[i/2] = 0.; }
 
	
 
	// construct new Nodes at the intersection points
 
	// unless they coincide with existing points
 
	for ( ItList::const_iterator i=new_node_locations.begin();
 
		 i!=new_node_locations.end();
 
		 i++) {
 
		
 
		// intersection between division axis
 
		// and line from this node to its predecessor
 
		
 
		// method used: http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/
 
		Vector v1 = from;
 
		Vector v2 = to;
 
		Vector v3 = *(**i);
 
		
 
		// get previous node
 
		list<Node *>::iterator nb=*i;
 
		if (nb == nodes.begin()) {
 
			nb = nodes.end();
 
		} 
 
		nb--;
 
		Vector v4=*( *nb ); 
 
		
 
		double denominator = 
 
		(v4.y - v3.y)*(v2.x - v1.x) - (v4.x - v3.x)*(v2.y - v1.y);
 
		
 
		double ua = 
 
		((v4.x - v3.x)*(v1.y - v3.y) - (v4.y - v3.y)*(v1.x -v3.x))/denominator;
 
		
 
		double intersec_x = v1.x + ua*(v2.x-v1.x);
 
		double intersec_y = v1.y + ua*(v2.y-v1.y);
 
		
 
		// construct a new node at intersec
 
		// we construct a vector temporarily,
 
		// until we are sure we are going to keep the node...
 
		// Node count is damaged if we construct superfluous nodes
 
		Vector *n=new Vector(intersec_x,intersec_y,0);
 
		
 
		div_edges[nnc].first=*nb;
 
		div_edges[nnc].second=**i;
 
		
 
		// Insert this new Node if it is far enough (5% of element length)
 
		// from one of the two existing nodes, else use existing node
 
		//
 
		// old, fixed value was: par.collapse_node_threshold = 0.05
 
		double collapse_node_threshold = 0.05;
 
    m->cells.pop_back();
 
    Cell::NCells()--;
 
    m->shuffled_cells.pop_back();
 
    return;
 
  }
 

	
 
  // We can be sure we only need two positions here because divisions
 
  // of non-convex cells are rejected above.
 
  Vector new_node[2];
 
  Node *new_node_ind[2];
 

	
 
  int new_node_flag[2];
 
  Edge div_edges[2];
 

	
 
  int nnc=0;
 

	
 
  Wall *div_wall[4];
 
  double orig_length[2];
 
  for (int i=0;i<4;i++) { div_wall[i]=0; orig_length[i/2] = 0.; }
 

	
 
  // construct new Nodes at the intersection points
 
  // unless they coincide with existing points
 
  for ( ItList::const_iterator i=new_node_locations.begin();
 
	i!=new_node_locations.end();
 
	i++) {
 

	
 
    // intersection between division axis
 
    // and line from this node to its predecessor
 

	
 
    // method used: http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/
 
    Vector v1 = from;
 
    Vector v2 = to;
 
    Vector v3 = *(**i);
 

	
 
    // get previous node
 
    list<Node *>::iterator nb=*i;
 
    if (nb == nodes.begin()) {
 
      nb = nodes.end();
 
    } 
 
    nb--;
 
    Vector v4=*( *nb ); 
 

	
 
    double denominator = 
 
      (v4.y - v3.y)*(v2.x - v1.x) - (v4.x - v3.x)*(v2.y - v1.y);
 

	
 
    double ua = 
 
      ((v4.x - v3.x)*(v1.y - v3.y) - (v4.y - v3.y)*(v1.x -v3.x))/denominator;
 

	
 
    double intersec_x = v1.x + ua*(v2.x-v1.x);
 
    double intersec_y = v1.y + ua*(v2.y-v1.y);
 

	
 
    // construct a new node at intersec
 
    // we construct a vector temporarily,
 
    // until we are sure we are going to keep the node...
 
    // Node count is damaged if we construct superfluous nodes
 
    Vector *n=new Vector(intersec_x,intersec_y,0);
 

	
 
    div_edges[nnc].first=*nb;
 
    div_edges[nnc].second=**i;
 

	
 
    // Insert this new Node if it is far enough (5% of element length)
 
    // from one of the two existing nodes, else use existing node
 
    //
 
    // old, fixed value was: par.collapse_node_threshold = 0.05
 
    double collapse_node_threshold = 0.05;
 
#ifdef FLEMING
 
		collapse_node_threshold = par.collapse_node_threshold;
 
    collapse_node_threshold = par.collapse_node_threshold;
 
#endif
 
		
 
		double elem_length = ( (*(**i)) - (*(*nb)) ).Norm();
 
		if ( ( *(**i) - *n ).Norm() < collapse_node_threshold  * elem_length ) {
 
			new_node_flag[nnc]=1;
 
			new_node[nnc] = *(**i);
 
			new_node_ind[nnc] = **i;
 
			//cerr << **i << endl ;
 
		} else 
 
			if ( (*(*nb) - *n).Norm() < collapse_node_threshold * elem_length ) {
 
				new_node_flag[nnc]=2;
 
				new_node[nnc] = *(*nb);
 
				new_node_ind[nnc] = *nb;
 
			} else {
 
				new_node_flag[nnc]=0;
 
				new_node[nnc] = *n;
 
			}
 
		
 
		nnc++;
 
		delete n;
 

	
 
    double elem_length = ( (*(**i)) - (*(*nb)) ).Norm();
 
    if ( ( *(**i) - *n ).Norm() < collapse_node_threshold  * elem_length ) {
 
      new_node_flag[nnc]=1;
 
      new_node[nnc] = *(**i);
 
      new_node_ind[nnc] = **i;
 
      //cerr << **i << endl ;
 
    } else 
 
      if ( (*(*nb) - *n).Norm() < collapse_node_threshold * elem_length ) {
 
	new_node_flag[nnc]=2;
 
	new_node[nnc] = *(*nb);
 
	new_node_ind[nnc] = *nb;
 
      } else {
 
	new_node_flag[nnc]=0;
 
	new_node[nnc] = *n;
 
      }
 

	
 
    nnc++;
 
    delete n;
 
  }
 

	
 

	
 
  for (int i=0;i<2;i++) {
 

	
 
    Cell *neighbor_cell=0; // we need this to split up the "Wall" objects.
 

	
 
    // for both divided edges: 
 
    //      insert its new node into all cells that own the divided edge
 
    // but only if it really is a new node:
 
    if (new_node_flag[i]!=0) {
 
      if (fix_cellwall) {
 
	(new_node_ind[i])->fixed = true;
 

	
 
	// all this we'll do later for the node set :-)
 
	/* (new_node_ind[i])->boundary = true;
 
	   (new_node_ind[i])->sam = true;
 
	   boundary = SAM;
 
	   daughter->boundary = SAM;
 
	   boundary_touched_flag = true;
 
	*/ 
 
      }
 

	
 
    } else {
 

	
 
      // (Construct a list of all owners:)
 
      // really construct the new node (if this is a new node)
 
      new_node_ind[i] = 
 
	m->AddNode(new Node (new_node[i]) );
 

	
 

	
 

	
 
      // if a new node is inserted into a fixed edge (i.e. in the petiole)
 
      // make the new node fixed as well
 
      (new_node_ind[i])->fixed = (div_edges[i].first)->fixed &&
 
	(div_edges[i].second)->fixed;
 

	
 
      // Insert Node into NodeSet if the div_edge is part of it.
 
      if (
 
	  (div_edges[i].first->node_set && div_edges[i].second->node_set) &&
 
	  (div_edges[i].first->node_set == div_edges[i].second->node_set))
 
	{
 
	  //cerr << "Inserting node into node set\n";
 
	  div_edges[i].first->node_set->AddNode( new_node_ind[i] );
 
	}
 
	
 
	
 
	for (int i=0;i<2;i++) {
 
		
 
		Cell *neighbor_cell=0; // we need this to split up the "Wall" objects.
 
		
 
		// for both divided edges: 
 
		//      insert its new node into all cells that own the divided edge
 
		// but only if it really is a new node:
 
		if (new_node_flag[i]!=0) {
 
			if (fix_cellwall) {
 
				(new_node_ind[i])->fixed = true;
 
				
 
				// all this we'll do later for the node set :-)
 
				/* (new_node_ind[i])->boundary = true;
 
				 (new_node_ind[i])->sam = true;
 
				 boundary = SAM;
 
				 daughter->boundary = SAM;
 
				 boundary_touched_flag = true;
 
				 */ 
 
			}
 
			
 
		} else {
 
			
 
			// (Construct a list of all owners:)
 
			// really construct the new node (if this is a new node)
 
			new_node_ind[i] = 
 
			m->AddNode(new Node (new_node[i]) );
 
			
 
			
 
			
 
			// if a new node is inserted into a fixed edge (i.e. in the petiole)
 
			// make the new node fixed as well
 
			(new_node_ind[i])->fixed = (div_edges[i].first)->fixed &&
 
			(div_edges[i].second)->fixed;
 
			
 
			// Insert Node into NodeSet if the div_edge is part of it.
 
			if (
 
				(div_edges[i].first->node_set && div_edges[i].second->node_set) &&
 
				(div_edges[i].first->node_set == div_edges[i].second->node_set))
 
			{
 
				//cerr << "Inserting node into node set\n";
 
				div_edges[i].first->node_set->AddNode( new_node_ind[i] );
 
			}
 
			
 
			// if the new wall should be fixed (i.e. immobile, or moving as
 
			// solid body), make it so, and make it part of the boundary. Using
 
			// this to make a nice initial condition by cutting off part of a
 
			// growing leaf.
 
			
 
			if (fix_cellwall) {
 
				(new_node_ind[i])->fixed = true;
 
				
 
				// All this we'll do later for the node set only
 
			}
 
			
 
			// if new node is inserted into the boundary
 
			// it will be part of the boundary, too
 

	
 
      // if the new wall should be fixed (i.e. immobile, or moving as
 
      // solid body), make it so, and make it part of the boundary. Using
 
      // this to make a nice initial condition by cutting off part of a
 
      // growing leaf.
 

	
 
      if (fix_cellwall) {
 
	(new_node_ind[i])->fixed = true;
 

	
 
	// All this we'll do later for the node set only
 
      }
 

	
 
      // if new node is inserted into the boundary
 
      // it will be part of the boundary, too
 

	
 
      new_node_ind[i]->UnsetBoundary();
 
      if ((div_edges[i].first->BoundaryP() && div_edges[i].second->BoundaryP()) && // Both edge nodes are boundary nodes AND
 
	  ((m->findNextBoundaryNode(div_edges[i].first))->Index() == div_edges[i].second->Index())){ // The boundary proceeds from first to second.
 

	
 
#ifdef QDEBUG
 
	qDebug() << "Index of the first node: " << div_edges[i].first->Index() << endl;
 
	qDebug() << "Index of the second node: " << div_edges[i].second->Index() << endl;
 
	qDebug() << "Boundary proceeds from: " <<  div_edges[i].first->Index() 
 
		 << "to: " << (m->findNextBoundaryNode(div_edges[i].first))->Index() << endl << endl;
 
#endif
 
	new_node_ind[i]->SetBoundary();
 

	
 
	// We will need to repair the boundary polygon later, since we will insert new nodes
 
	//cerr << "Boundary touched for Node " << new_node_ind[i]->Index() << "\n";
 
	boundary_touched_flag=true;
 

	
 
			new_node_ind[i]->UnsetBoundary();
 
			if ((div_edges[i].first->BoundaryP() && div_edges[i].second->BoundaryP()) && // Both edge nodes are boundary nodes AND
 
			     ((m->findNextBoundaryNode(div_edges[i].first))->Index() == div_edges[i].second->Index())){ // The boundary proceeds from first to second.
 
	// and insert it into the boundary_polygon
 
	// find the position of the first node in the boundary
 
	list<Node *>::iterator ins_pos = find
 
	  (m->boundary_polygon->nodes.begin(),
 
	   m->boundary_polygon->nodes.end(),
 
	   div_edges[i].first);
 
	// ... second node comes before or after it ...
 
	if (*(++ins_pos!=m->boundary_polygon->nodes.end()?
 
	      ins_pos:m->boundary_polygon->nodes.begin())!=div_edges[i].second) {
 

	
 
                                #ifdef QDEBUG
 
			        qDebug() << "Index of the first node: " << div_edges[i].first->Index() << endl;
 
			        qDebug() << "Index of the second node: " << div_edges[i].second->Index() << endl;
 
			        qDebug() << "Boundary proceeds from: " <<  div_edges[i].first->Index() 
 
				         << "to: " << (m->findNextBoundaryNode(div_edges[i].first))->Index() << endl << endl;
 
                                #endif
 
			        new_node_ind[i]->SetBoundary();
 
	  m->boundary_polygon->nodes.insert(((ins_pos--)!=m->boundary_polygon->nodes.begin()?ins_pos:(--m->boundary_polygon->nodes.end())), new_node_ind[i]);
 

	
 
				// We will need to repair the boundary polygon later, since we will insert new nodes
 
				//cerr << "Boundary touched for Node " << new_node_ind[i]->Index() << "\n";
 
				boundary_touched_flag=true;
 
				
 
				// and insert it into the boundary_polygon
 
				// find the position of the first node in the boundary
 
				list<Node *>::iterator ins_pos = find
 
				(m->boundary_polygon->nodes.begin(),
 
				 m->boundary_polygon->nodes.end(),
 
				 div_edges[i].first);
 
				// ... second node comes before or after it ...
 
				if (*(++ins_pos!=m->boundary_polygon->nodes.end()?
 
					  ins_pos:m->boundary_polygon->nodes.begin())!=div_edges[i].second) {
 
					
 
					m->boundary_polygon->nodes.insert(((ins_pos--)!=m->boundary_polygon->nodes.begin()?ins_pos:(--m->boundary_polygon->nodes.end())), new_node_ind[i]);
 
					
 
					// .. set the neighbors of the new node ...
 
					// in this case e.second and e.first are inverted
 
				} else {
 
					// insert before second node, so leave ins_pos as it is,
 
					// that is: incremented
 
					m->boundary_polygon->nodes.insert(ins_pos, new_node_ind[i]);	
 
					// .. set the neighbors of the new node ...
 
				}
 
			}
 
			
 
			list<Neighbor> owners;
 
			
 
			// push all cells owning the two nodes of the divides edges
 
			// onto a list
 
	  // .. set the neighbors of the new node ...
 
	  // in this case e.second and e.first are inverted
 
	} else {
 
	  // insert before second node, so leave ins_pos as it is,
 
	  // that is: incremented
 
	  m->boundary_polygon->nodes.insert(ins_pos, new_node_ind[i]);	
 
	  // .. set the neighbors of the new node ...
 
	}
 
      }
 

	
 
      list<Neighbor> owners;
 

	
 
			copy((div_edges[i].first)->owners.begin(),
 
				 (div_edges[i].first)->owners.end(),
 
				 back_inserter(owners));
 
			copy((div_edges[i].second)->owners.begin(),
 
				 (div_edges[i].second)->owners.end(),
 
				 back_inserter(owners));
 
			
 
			
 
			// find first non-self duplicate in the owners: 
 
			// cells owning the same two nodes
 
			// share an edge with me
 
			owners.sort( mem_fun_ref( &Neighbor::Cmp ) );
 
      // push all cells owning the two nodes of the divides edges
 
      // onto a list
 

	
 
      copy((div_edges[i].first)->owners.begin(),
 
	   (div_edges[i].first)->owners.end(),
 
	   back_inserter(owners));
 
      copy((div_edges[i].second)->owners.begin(),
 
	   (div_edges[i].second)->owners.end(),
 
	   back_inserter(owners));
 

	
 

	
 
      // find first non-self duplicate in the owners: 
 
      // cells owning the same two nodes
 
      // share an edge with me
 
      owners.sort( mem_fun_ref( &Neighbor::Cmp ) );
 

	
 

	
 
                        #ifdef QDEBUG  
 
			list<Neighbor> unique_owners;
 
			copy(owners.begin(), owners.end(), back_inserter(unique_owners));
 
			unique_owners.unique( mem_fun_ref( &Neighbor::Eq ) );
 
			qDebug() << "The dividing edge nodes: " << div_edges[i].first->Index() << " and " << div_edges[i].second->Index() << " are owned by cells: ";
 
			// spit out each owners' cell index
 
			foreach(Neighbor neighbor, unique_owners){
 
			  qDebug() << neighbor.cell->Index() << "  ";
 
			}
 
			qDebug() << endl;
 
                        #endif
 
#ifdef QDEBUG  
 
      list<Neighbor> unique_owners;
 
      copy(owners.begin(), owners.end(), back_inserter(unique_owners));
 
      unique_owners.unique( mem_fun_ref( &Neighbor::Eq ) );
 
      qDebug() << "The dividing edge nodes: " << div_edges[i].first->Index() 
 
	       << " and " << div_edges[i].second->Index() << " are owned by cells: ";
 

	
 
      // spit out each owners' cell index
 
      foreach(Neighbor neighbor, unique_owners){
 
	qDebug() << neighbor.cell->Index() << "  ";
 
      }
 
      qDebug() << endl;
 
#endif
 

	
 
      // Search through the sorted list of edge node owners looking for duplicate pairs. Each pair represents an actual edge owner.
 
      list<Neighbor> edge_owners;
 
      list<Neighbor>::iterator it;
 
      for (it=owners.begin(); it!=owners.end(); it++) {
 
	it = adjacent_find(it, owners.end(), neighbor_cell_eq);
 
	if (it == owners.end()) break; // bail if reach the end of the list
 
#ifdef QDEBUG
 
	qDebug() << "Considering: " << it->cell->Index() << " as a possible edge owner." << endl;
 
#endif
 
	if (it->cell->Index() != this->Index()) {
 
#ifdef QDEBUG
 
	  qDebug() << "Adding: " << it->cell->Index() << " to the list of edge owners." << endl;
 
#endif
 
	  edge_owners.push_back(*it);
 
	}
 
      } 
 

	
 
			// Search through the sorted list of edge node owners looking for duplicate pairs. Each pair represents an actual edge owner.
 
			list<Neighbor> edge_owners;
 
			list<Neighbor>::iterator it;
 
			for (it=owners.begin(); it!=owners.end(); it++) {
 
			  it = adjacent_find(it, owners.end(), neighbor_cell_eq);
 
			  if (it == owners.end()) break; // bail if reach the end of the list
 
                          #ifdef QDEBUG
 
			  qDebug() << "Considering: " << it->cell->Index() << " as a possible edge owner." << endl;
 
                          #endif
 
			  if (it->cell->Index() != this->Index()) {
 
                            #ifdef QDEBUG
 
			    qDebug() << "Adding: " << it->cell->Index() << " to the list of edge owners." << endl;
 
                            #endif
 
			    edge_owners.push_back(*it);
 
			  }
 
			} 
 
      if (edge_owners.size() > 1){
 
	// Remove the boundary polygon - if its there
 
	list<Neighbor>::iterator it;
 
	if ((it = find_if (edge_owners.begin(), edge_owners.end(), bind2nd(mem_fun_ref(&Neighbor::CellEquals), -1)))
 
	    != edge_owners.end()) {
 
#ifdef QDEBUG
 
	  qDebug() << "deleating: " << it->cell->Index() << " from the list of edge owners." << endl;
 
#endif
 
	  edge_owners.erase(it);
 
	}
 
      }
 

	
 
#ifdef QDEBUG
 
      qDebug() << "The edge owners list has: " << edge_owners.size() << " elements" << endl;
 
#endif
 

	
 
			if (edge_owners.size() > 1){
 
			  // Remove the boundary polygon - if its there
 
			  list<Neighbor>::iterator it;
 
			  if ((it = find_if (edge_owners.begin(), edge_owners.end(), bind2nd(mem_fun_ref(&Neighbor::CellEquals), -1))) != edge_owners.end()) {
 
                            #ifdef QDEBUG
 
			    qDebug() << "deleating: " << it->cell->Index() << " from the list of edge owners." << endl;
 
                            #endif
 
			    edge_owners.erase(it);
 
			  }
 
			}
 
      // Since the list should always contain exactly one element, pass it on as an iterator
 
      list<Neighbor>::iterator c = (edge_owners.size() != 0) ? edge_owners.begin() : edge_owners.end();
 

	
 
      // (can we have more than one neighboring cell here??)
 
      if (c!=owners.end()) { 
 
	neighbor_cell = c->cell;
 
	if (!c->cell->BoundaryPolP()) {
 

	
 
                        #ifdef QDEBUG
 
			qDebug() << "The edge owners list has: " << edge_owners.size() << " elements" << endl;
 
			#endif
 
	  // find correct position in the cells node list
 
	  // to insert the new node
 
	  list<Node *>::iterator ins_pos = find
 
	    (neighbor_cell->nodes.begin(),
 
	     neighbor_cell->nodes.end(),
 
	     div_edges[i].first);
 

	
 
	  neighbor_cell->nodes.insert(ins_pos, new_node_ind[i]);
 
	  neighbor_cell->ConstructConnections();
 

	
 
			// Since the list should always contain exactly one element, pass it on as an iterator
 
			list<Neighbor>::iterator c = (edge_owners.size() != 0) ? edge_owners.begin() : edge_owners.end();
 
	  // give walls to daughter later
 
	}
 
      } else {
 
	neighbor_cell = 0;
 
      }
 
    }
 

	
 
    // Split the Wall with the neighboring cell
 

	
 
    // if the neighbor cell has not yet been identified above, do it now
 
    if (neighbor_cell == 0) {
 

	
 
      list<Neighbor> owners;
 

	
 
			// (can we have more than one neighboring cell here??)
 
			if (c!=owners.end()) { 
 
				neighbor_cell = c->cell;
 
				if (!c->cell->BoundaryPolP()) {
 
      // push all cells owning the two nodes of the divides edges
 
      // onto a list
 
      copy((div_edges[i].first)->owners.begin(),
 
	   (div_edges[i].first)->owners.end(),
 
	   back_inserter(owners));
 
      copy((div_edges[i].second)->owners.begin(),
 
	   (div_edges[i].second)->owners.end(),
 
	   back_inserter(owners));
 

	
 

	
 
      // find first non-self duplicate in the owners: 
 
      // cells owning the same two nodes
 
      // share an edge with me
 
      owners.sort( mem_fun_ref( &Neighbor::Cmp ) );
 

	
 
					// find correct position in the cells node list
 
					// to insert the new node
 
					list<Node *>::iterator ins_pos = find
 
					(neighbor_cell->nodes.begin(),
 
					 neighbor_cell->nodes.end(),
 
					 div_edges[i].first);
 
					
 
					neighbor_cell->nodes.insert(ins_pos, new_node_ind[i]);
 
					neighbor_cell->ConstructConnections();
 
					
 
					// give walls to daughter later
 
			  }
 
			} else {
 
				neighbor_cell = 0;
 
			}
 
		}
 
		
 
		// Split the Wall with the neighboring cell
 
		
 
		// if the neighbor cell has not yet been identified above, do it now
 
		if (neighbor_cell == 0) {
 
			
 
			list<Neighbor> owners;
 
			
 
			// push all cells owning the two nodes of the divides edges
 
			// onto a list
 
			copy((div_edges[i].first)->owners.begin(),
 
				 (div_edges[i].first)->owners.end(),
 
				 back_inserter(owners));
 
			copy((div_edges[i].second)->owners.begin(),
 
				 (div_edges[i].second)->owners.end(),
 
				 back_inserter(owners));
 
			
 
			
 
			// find first non-self duplicate in the owners: 
 
			// cells owning the same two nodes
 
			// share an edge with me
 
			owners.sort( mem_fun_ref( &Neighbor::Cmp ) );
 
      list<Neighbor>::iterator c;
 
      for (c=owners.begin();
 
	   c!=owners.end();
 
	   c++) {
 
	c=adjacent_find(c,owners.end(),neighbor_cell_eq);
 
	if (c->cell->Index() != this->Index() || c==owners.end()) break;
 
      }
 

	
 
      if (c!=owners.end())
 
	neighbor_cell = c->cell;
 
      else 
 
	neighbor_cell = 0;
 
    }
 

	
 

	
 
    if (neighbor_cell /* && !neighbor_cell->BoundaryPolP() */) {
 

	
 
      //cerr << "Cell "  << index << " says: neighboring cell is " << neighbor_cell->index << endl;
 

	
 
      /*************** 1. Find the correct wall element  ********************/
 

	
 
      list<Wall *>::iterator w, start_search;
 
      w = start_search = walls.begin();
 
      do {
 
	// Find wall between this cell and neighbor cell
 
	w = find_if( start_search, walls.end(), bind2nd (mem_fun( &Wall::is_wall_of_cell_p ), neighbor_cell ) );
 
	start_search = w; start_search++; // continue searching at next element
 
      } while ( w!=walls.end() && !(*w)->IntersectsWithDivisionPlaneP( from, to ) ); // go on until we find the right one.
 

	
 
      if (w == walls.end()) {
 
#ifdef QDEBUG
 
	qDebug() << "Whoops, wall element not found...!" << endl;
 
	qDebug() << "Cell ID: " << neighbor_cell->Index() << endl;
 
	qDebug() << "My cell ID: " << Index() << endl;
 
#endif
 
      } else {
 

	
 
	// 2. Split it up, if we should (sometimes, the new node coincides with an existing node so
 
	// we should not split up the Wall)
 

	
 
	if (new_node_ind[i]!=(*w)->n1 && new_node_ind[i]!=(*w)->n2) {
 

	
 
	  Wall *new_wall;
 

	
 
			list<Neighbor>::iterator c;
 
			for (c=owners.begin();
 
				 c!=owners.end();
 
				 c++) {
 
				c=adjacent_find(c,owners.end(),neighbor_cell_eq);
 
				if (c->cell->Index() != this->Index() || c==owners.end()) break;
 
			}
 
			
 
			if (c!=owners.end())
 
				neighbor_cell = c->cell;
 
			else 
 
				neighbor_cell = 0;
 
		}
 
		
 
		
 
		if (neighbor_cell /* && !neighbor_cell->BoundaryPolP() */) {
 
			
 
			//cerr << "Cell "  << index << " says: neighboring cell is " << neighbor_cell->index << endl;
 
			
 
			/*************** 1. Find the correct wall element  ********************/
 
			
 
			list<Wall *>::iterator w, start_search;
 
			w = start_search = walls.begin();
 
			do {
 
				// Find wall between this cell and neighbor cell
 
				w = find_if( start_search, walls.end(), bind2nd (mem_fun( &Wall::is_wall_of_cell_p ), neighbor_cell ) );
 
				start_search = w; start_search++; // continue searching at next element
 
			} while ( w!=walls.end() && !(*w)->IntersectsWithDivisionPlaneP( from, to ) ); // go on until we find the right one.
 
			
 
			if (w == walls.end()) {
 
			        #ifdef QDEBUG
 
			        qDebug() << "Whoops, wall element not found...!" << endl;
 
			        qDebug() << "Cell ID: " << neighbor_cell->Index() << endl;
 
				qDebug() << "My cell ID: " << Index() << endl;
 
                                #endif
 
			} else {
 
				
 
				// 2. Split it up, if we should (sometimes, the new node coincides with an existing node so
 
				// we should not split up the Wall)
 
				
 
				if (new_node_ind[i]!=(*w)->n1 && new_node_ind[i]!=(*w)->n2) {
 
					
 
					Wall *new_wall;
 
					
 
					// keep the length of the original wall; we need it to equally divide the transporter concentrations
 
					// over the two daughter walls
 
					(*w)->SetLength(); // make sure we've got the current length
 
					orig_length[i] = (*w)->Length();
 
					//cerr << "Original length is " << orig_length[i] << endl;
 
					if ((*w)->c1 == this ) {
 
						
 
						//  cerr << "Cell " << (*w)->c1->Index() << " splits up wall " << *(*w) << ", into: " << endl;
 
						new_wall = new Wall( (*w)->n1, new_node_ind[i], this, neighbor_cell);
 
						(*w)->n1 = new_node_ind[i];
 
						
 
						//  cerr << "wall " << *(*w) << ", and new wall " << *new_wall << endl;
 
						
 
					} else {
 
						new_wall = new Wall( (*w)->n1, new_node_ind[i], neighbor_cell, this);
 
						
 
						(*w)->n1 = new_node_ind[i];
 
					}
 
					
 
					
 
					// 3. Give wall elements to appropriate cells
 
					if (new_wall->n1 != new_wall->n2) {
 
						
 
						if (par.copy_wall)
 
							new_wall->CopyWallContents(**w);
 
						else {
 
							// If wall contents are not copied, decide randomly which wall will be the "parent"
 
							// otherwise we will get biases (to the left), for example in the meristem growth model
 
							if (RANDOM()<0.5) {
 
								new_wall->SwapWallContents(*w);
 
							}
 
						}
 
						AddWall(new_wall);
 
						// cerr << "Building new wall: this=" << Index() << ", neighbor_cell = " << neighbor_cell->Index() << endl;
 
						
 
						neighbor_cell->AddWall( new_wall);
 
						//cerr << "Existing wall: c1 = " << (*w)->c1->Index() << ", neighbor_cell = " << (*w)->c2->Index() << endl;
 
						
 
						// Remember the addresses of the new walls
 
						div_wall[2*i+0] = *w;
 
						div_wall[2*i+1] = new_wall;
 
						
 
						// we will correct the transporter concentrations later in this member function, after division
 
						// First the new nodes should be inserted into the cells, before we can calculate wall lengths
 
						// Remember that cell walls can be bent, so have a bigger length than the Euclidean distance n1->n2
 
						
 
					} else {
 
						delete new_wall;
 
					}
 
				}
 
			}
 
		}
 
	}  // closing loop over the two divided edges (for (int i=0;i<2;i++) )
 
	
 
	// move half of the nodes to the daughter
 
	{
 
		//cerr << "Daughter: ";
 
		list<Node *>::iterator start, stop;
 
		
 
		start=new_node_locations.front();
 
		
 
		//cerr << "*new_node_locations.front() = " << *new_node_locations.front() << endl;
 
		if (new_node_flag[0]==1) {
 
			start++;
 
			if (start==nodes.end())
 
				start=nodes.begin();
 
		}  
 
		
 
		stop=new_node_locations.back();
 
		if (new_node_flag[1]==2) {
 
			if (stop==nodes.begin())
 
				stop=nodes.end();
 
			stop--;
 
		}
 
		list<Node *>::iterator i=start;
 
		while ( i!=stop) {
 
			
 
			// give the node to the daughter
 
			// (find references to parent cell from this node,
 
			// and remove them)
 
			list<Neighbor>::iterator neighb_with_this_cell=
 
			find_if((*i)->owners.begin(),
 
					(*i)->owners.end(),
 
				bind2nd(mem_fun_ref( &Neighbor::CellEquals ),this->Index() )  );
 
			if (neighb_with_this_cell==(*i)->owners.end()) {
 
			        #ifdef QDEBUG
 
			  qDebug() << "not found" << endl;
 
                                #endif
 
				abort();
 
			}
 
			
 
			(*i)->owners.erase(neighb_with_this_cell);
 
			
 
			daughter->nodes.push_back( *i );
 
			
 
			
 
			i++;
 
			if (i==nodes.end())
 
				i=nodes.begin();
 
		};
 
	  // keep the length of the original wall; we need it to equally divide the transporter concentrations
 
	  // over the two daughter walls
 
	  (*w)->SetLength(); // make sure we've got the current length
 
	  orig_length[i] = (*w)->Length();
 
	  //cerr << "Original length is " << orig_length[i] << endl;
 
	  if ((*w)->c1 == this ) {
 

	
 
	    //  cerr << "Cell " << (*w)->c1->Index() << " splits up wall " << *(*w) << ", into: " << endl;
 
	    new_wall = new Wall( (*w)->n1, new_node_ind[i], this, neighbor_cell);
 
	    (*w)->n1 = new_node_ind[i];
 

	
 
	    //  cerr << "wall " << *(*w) << ", and new wall " << *new_wall << endl;
 

	
 
	  } else {
 
	    new_wall = new Wall( (*w)->n1, new_node_ind[i], neighbor_cell, this);
 

	
 
	    (*w)->n1 = new_node_ind[i];
 
	  }
 

	
 

	
 
	  // 3. Give wall elements to appropriate cells
 
	  if (new_wall->n1 != new_wall->n2) {
 

	
 
	    if (par.copy_wall)
 
	      new_wall->CopyWallContents(**w);
 
	    else {
 
	      // If wall contents are not copied, decide randomly which wall will be the "parent"
 
	      // otherwise we will get biases (to the left), for example in the meristem growth model
 
	      if (RANDOM()<0.5) {
 
		new_wall->SwapWallContents(*w);
 
	      }
 
	    }
 
	    AddWall(new_wall);
 
	    // cerr << "Building new wall: this=" << Index() << ", neighbor_cell = " << neighbor_cell->Index() << endl;
 

	
 
	    neighbor_cell->AddWall( new_wall);
 
	    //cerr << "Existing wall: c1 = " << (*w)->c1->Index() << ", neighbor_cell = " << (*w)->c2->Index() << endl;
 

	
 
	    // Remember the addresses of the new walls
 
	    div_wall[2*i+0] = *w;
 
	    div_wall[2*i+1] = new_wall;
 

	
 
	    // we will correct the transporter concentrations later in this member function, after division
 
	    // First the new nodes should be inserted into the cells, before we can calculate wall lengths
 
	    // Remember that cell walls can be bent, so have a bigger length than the Euclidean distance n1->n2
 

	
 
	  } else {
 
	    delete new_wall;
 
	  }
 
	}
 
	
 
	// new node list of parent
 
	list<Node *> new_nodes_parent;
 
	
 
	// half of the nodes stay with the parent
 
	{
 
		list<Node *>::iterator start, stop;
 
		start=new_node_locations.back();
 
		if (new_node_flag[1]==1) {
 
			start++;
 
			if (start==nodes.end())
 
				start=nodes.begin();
 
		}
 
		stop=new_node_locations.front();
 
		if (new_node_flag[0]==2) {
 
			if (stop==nodes.begin())
 
				stop=nodes.end();
 
			stop--;
 
		}
 
		
 
		list<Node *>::iterator i=start;
 
		while (i!=stop) {
 
			new_nodes_parent.push_back( *i );
 
			
 
			i++;
 
			if (i==nodes.end()) 
 
				i = nodes.begin();
 
		};
 
	}
 
      }
 
    }
 
  }  // closing loop over the two divided edges (for (int i=0;i<2;i++) )
 

	
 
  // move half of the nodes to the daughter
 
  {
 
    //cerr << "Daughter: ";
 
    list<Node *>::iterator start, stop;
 

	
 
    start=new_node_locations.front();
 

	
 
    //cerr << "*new_node_locations.front() = " << *new_node_locations.front() << endl;
 
    if (new_node_flag[0]==1) {
 
      start++;
 
      if (start==nodes.end())
 
	start=nodes.begin();
 
    }  
 

	
 
    stop=new_node_locations.back();
 
    if (new_node_flag[1]==2) {
 
      if (stop==nodes.begin())
 
	stop=nodes.end();
 
      stop--;
 
    }
 
    list<Node *>::iterator i=start;
 
    while ( i!=stop) {
 

	
 
      // give the node to the daughter
 
      // (find references to parent cell from this node,
 
      // and remove them)
 
      list<Neighbor>::iterator neighb_with_this_cell=
 
	find_if((*i)->owners.begin(),
 
		(*i)->owners.end(),
 
		bind2nd(mem_fun_ref( &Neighbor::CellEquals ),this->Index() )  );
 
      if (neighb_with_this_cell==(*i)->owners.end()) {
 

	
 
#ifdef QDEBUG
 
	qDebug() << "not found" << endl;
 
#endif
 
	abort();
 
      }
 

	
 
      (*i)->owners.erase(neighb_with_this_cell);
 

	
 
      daughter->nodes.push_back( *i );
 

	
 

	
 
	// insert shared wall
 
	// insert shared nodes on surface of parent cell
 
	new_nodes_parent.push_back( new_node_ind[0] );
 
	daughter->nodes.push_back ( new_node_ind[1] );
 
	
 
	// optionally add the new node to the nodeset (passed by pointer)
 
	// (in this way we can move the NodeSet as a whole; useful for a fixed cutting line)
 
	if (node_set) {
 
		node_set->AddNode( new_node_ind[0] );
 
	}
 
	
 
      i++;
 
      if (i==nodes.end())
 
	i=nodes.begin();
 
    };
 
  }
 

	
 
  // new node list of parent
 
  list<Node *> new_nodes_parent;
 

	
 
  // half of the nodes stay with the parent
 
  {
 
    list<Node *>::iterator start, stop;
 
    start=new_node_locations.back();
 
    if (new_node_flag[1]==1) {
 
      start++;
 
      if (start==nodes.end())
 
	start=nodes.begin();
 
    }
 
    stop=new_node_locations.front();
 
    if (new_node_flag[0]==2) {
 
      if (stop==nodes.begin())
 
	stop=nodes.end();
 
      stop--;
 
    }
 

	
 
    list<Node *>::iterator i=start;
 
    while (i!=stop) {
 
      new_nodes_parent.push_back( *i );
 

	
 
      i++;
 
      if (i==nodes.end()) 
 
	i = nodes.begin();
 
    };
 
  }
 

	
 
  // insert shared wall
 
  // insert shared nodes on surface of parent cell
 
  new_nodes_parent.push_back( new_node_ind[0] );
 
  daughter->nodes.push_back ( new_node_ind[1] );
 

	
 
  // optionally add the new node to the nodeset (passed by pointer)
 
  // (in this way we can move the NodeSet as a whole; useful for a fixed cutting line)
 
  if (node_set) {
 
    node_set->AddNode( new_node_ind[0] );
 
  }
 

	
 
#define MULTIPLE_NODES
 
#ifdef MULTIPLE_NODES
 
	// intermediate, extra nodes
 
	// Calculate distance between the two new nodes
 
	double dist=( new_node[1] - new_node[0] ).Norm();
 
	//bool fixed_wall = (new_node_ind[0])->fixed && (new_node_ind[1])->fixed;
 
	bool fixed_wall = false;
 
	
 
	// Estimate number of extra nodes in wall
 
	// factor 4 is to keep tension on the walls;
 
	// this is a hidden parameter and should be made explicit
 
	// later on.
 
	int n=(int)((dist/Node::target_length)/4+0.5);
 
	
 
	Vector nodevec = ( new_node[1]- new_node[0]).Normalised();
 
	
 
	double element_length = dist/(double)(n+1);
 
	
 
	// note that wall nodes need to run in inverse order in parent
 
	list<Node *>::iterator ins_pos = daughter->nodes.end();
 
	for (int i=1;i<=n;i++) {
 
		Node *node=
 
		m->AddNode( new Node( new_node[0] + i*element_length*nodevec ) );
 
		
 
		node->fixed=fixed_wall;
 
		
 
		if (!fix_cellwall)
 
			node->boundary = false;
 
		else {
 
			node->fixed = true;
 
		}
 
		
 
		ins_pos=daughter->nodes.insert(ins_pos, node );
 
		new_nodes_parent.push_back( node );
 
		
 
		// optionally add the new node to the nodeset (passed by pointer)
 
		// (in this way we can move the NodeSet as a whole; useful for a fixed cutting line)
 
		if (node_set) {
 
			node_set->AddNode( node );
 
		}
 
		
 
	}
 
  // intermediate, extra nodes
 
  // Calculate distance between the two new nodes
 
  double dist=( new_node[1] - new_node[0] ).Norm();
 
  //bool fixed_wall = (new_node_ind[0])->fixed && (new_node_ind[1])->fixed;
 
  bool fixed_wall = false;
 

	
 
  // Estimate number of extra nodes in wall
 
  // factor 4 is to keep tension on the walls;
 
  // this is a hidden parameter and should be made explicit
 
  // later on.
 
  int n=(int)((dist/Node::target_length)/4+0.5);
 

	
 
  Vector nodevec = ( new_node[1]- new_node[0]).Normalised();
 

	
 
  double element_length = dist/(double)(n+1);
 

	
 
  // note that wall nodes need to run in inverse order in parent
 
  list<Node *>::iterator ins_pos = daughter->nodes.end();
 
  for (int i=1;i<=n;i++) {
 
    Node *node=
 
      m->AddNode( new Node( new_node[0] + i*element_length*nodevec ) );
 

	
 
    node->fixed=fixed_wall;
 

	
 
    if (!fix_cellwall)
 
      node->boundary = false;
 
    else {
 
      node->fixed = true;
 
    }
 

	
 
    ins_pos=daughter->nodes.insert(ins_pos, node );
 
    new_nodes_parent.push_back( node );
 

	
 
    // optionally add the new node to the nodeset (passed by pointer)
 
    // (in this way we can move the NodeSet as a whole; useful for a fixed cutting line)
 
    if (node_set) {
 
      node_set->AddNode( node );
 
    }
 

	
 
  }
 
#endif
 
	daughter->nodes.push_back( new_node_ind[0] );
 
	new_nodes_parent.push_back( new_node_ind[1] );
 
	
 
	// optionally add the new node to the nodeset (passed by pointer)
 
	// (in this way we can move the NodeSet as a whole; useful for a fixed cutting line)
 
	if (node_set) {
 
		node_set->AddNode( new_node_ind[1] );
 
	}
 
	
 
	// move the new nodes to the parent
 
	nodes.clear();
 
	copy( new_nodes_parent.begin(), 
 
		 new_nodes_parent.end(), 
 
		 back_inserter(nodes) );
 
	
 
	
 
	// Repair cell lists of Nodes, and node connectivities
 
	ConstructConnections();
 
	daughter->ConstructConnections();
 
	
 
	if (boundary_touched_flag) {
 
		m->boundary_polygon->ConstructConnections();
 
	} 
 
	
 
	// collecting neighbors of divided cell
 
	list<CellBase *> broken_neighbors;
 
	
 
	// this cell's old neighbors
 
	copy(neighbors.begin(), neighbors.end(), back_inserter(broken_neighbors) );
 
	
 
	// this cell
 
	broken_neighbors.push_back(this);
 
	
 
	// its daughter
 
	broken_neighbors.push_back(daughter);
 
	
 
	
 
	
 
	// Recalculate area of parent and daughter
 
	area = CalcArea();
 
	daughter->area = daughter->CalcArea();
 
	
 
	SetIntegrals();
 
	daughter->SetIntegrals();
 
	
 
    
 
	
 
	// Add a "Cell Wall" for diffusion algorithms
 
	Wall *wall = new Wall( new_node_ind[0], new_node_ind[1], this, daughter );
 
	
 
	AddWall( wall );
 
	
 
	daughter->AddWall( wall );
 
	
 
	//cerr << "Correct walls of cell " << Index() << " and daughter " << daughter->Index() << endl;
 
	
 
	// Move Walls to daughter cell
 
	list <Wall *> copy_walls = walls;
 
	for (list<Wall *>::iterator w = copy_walls.begin();
 
		 w!=copy_walls.end();
 
		 w++) {
 
		
 
		//cerr << "Doing wall, before:  " << **w << endl;
 
		
 
		//  checks the nodes of the wall and gives it away if appropriate
 
		(*w)->CorrectWall ( );
 
		
 
		//cerr << "and after: " << **w << endl;
 
		
 
	}
 
	
 
	
 
	
 
	// Correct tranporterconcentrations of divided walls
 
	for (int i=0;i<4;i++) {
 
		if (div_wall[i]) {
 
			div_wall[i]->SetLength();
 
			div_wall[i]->CorrectTransporters(orig_length[i/2]);
 
		}
 
	}
 
	
 
	//cerr << "Cell " << index << " has been dividing, and gave birth to Cell " << daughter->index << endl;
 
	
 
	// now reconstruct neighbor list for all "broken" neighbors
 
	
 
	for (list<CellBase *>::iterator i=broken_neighbors.begin();
 
		 i!=broken_neighbors.end();i++) {
 
		((Cell *)(*i))->ConstructNeighborList();
 
	}
 
	
 
	
 
	ConstructNeighborList();
 
	daughter->ConstructNeighborList();
 
	
 
	m->plugin->OnDivide(&parent_info, daughter, this);
 
	
 
	daughter->div_counter=(++div_counter);
 
	
 
	
 
  daughter->nodes.push_back( new_node_ind[0] );
 
  new_nodes_parent.push_back( new_node_ind[1] );
 

	
 
  // optionally add the new node to the nodeset (passed by pointer)
 
  // (in this way we can move the NodeSet as a whole; useful for a fixed cutting line)
 
  if (node_set) {
 
    node_set->AddNode( new_node_ind[1] );
 
  }
 

	
 
  // move the new nodes to the parent
 
  nodes.clear();
 
  copy( new_nodes_parent.begin(), 
 
	new_nodes_parent.end(), 
 
	back_inserter(nodes) );
 

	
 

	
 
  // Repair cell lists of Nodes, and node connectivities
 
  ConstructConnections();
 
  daughter->ConstructConnections();
 

	
 
  if (boundary_touched_flag) {
 
    m->boundary_polygon->ConstructConnections();
 
  } 
 

	
 
  // collecting neighbors of divided cell
 
  list<CellBase *> broken_neighbors;
 

	
 
  // this cell's old neighbors
 
  copy(neighbors.begin(), neighbors.end(), back_inserter(broken_neighbors) );
 

	
 
  // this cell
 
  broken_neighbors.push_back(this);
 

	
 
  // its daughter
 
  broken_neighbors.push_back(daughter);
 

	
 
  // Recalculate area of parent and daughter
 
  area = CalcArea();
 
  daughter->area = daughter->CalcArea();
 

	
 
  SetIntegrals();
 
  daughter->SetIntegrals();
 

	
 
  // Add a "Cell Wall" for diffusion algorithms
 
  Wall *wall = new Wall( new_node_ind[0], new_node_ind[1], this, daughter );
 

	
 
  AddWall( wall );
 

	
 
  daughter->AddWall( wall );
 

	
 
  //cerr << "Correct walls of cell " << Index() << " and daughter " << daughter->Index() << endl;
 

	
 
  // Move Walls to daughter cell
 
  list <Wall *> copy_walls = walls;
 
  for (list<Wall *>::iterator w = copy_walls.begin();
 
       w!=copy_walls.end();
 
       w++) {
 

	
 
    //cerr << "Doing wall, before:  " << **w << endl;
 

	
 
    //  checks the nodes of the wall and gives it away if appropriate
 
    (*w)->CorrectWall ( );
 

	
 
    //cerr << "and after: " << **w << endl;
 

	
 
  }
 

	
 
  // Correct tranporterconcentrations of divided walls
 
  for (int i=0;i<4;i++) {
 
    if (div_wall[i]) {
 
      div_wall[i]->SetLength();
 
      div_wall[i]->CorrectTransporters(orig_length[i/2]);
 
    }
 
  }
 

	
 
  //cerr << "Cell " << index << " has been dividing, and gave birth to Cell " << daughter->index << endl;
 

	
 
  // now reconstruct neighbor list for all "broken" neighbors
 

	
 
  for (list<CellBase *>::iterator i=broken_neighbors.begin();
 
       i!=broken_neighbors.end();i++) {
 
    ((Cell *)(*i))->ConstructNeighborList();
 
  }
 

	
 
  ConstructNeighborList();
 
  daughter->ConstructNeighborList();
 

	
 
  m->plugin->OnDivide(&parent_info, daughter, this);
 

	
 
  daughter->div_counter=(++div_counter);
 
}
 

	
 
// Move the whole cell
 
void Cell::Move(const Vector T) {
 
	
 
    for (list<Node *>::const_iterator i=nodes.begin();
 
		 i!=nodes.end();
 
		 i++) {
 
		*(*i)+=T;
 
    }
 

	
 
  for (list<Node *>::const_iterator i=nodes.begin();
 
       i!=nodes.end();
 
       i++) {
 
    *(*i)+=T;
 
  }
 
}
 

	
 
double Cell::Displace(double dx, double dy, double dh) {
 
	
 
	// Displace whole cell, add resulting energy to dh,
 
	// and accept displacement if energetically favorable
 
	// 
 
	// Method is called if a "fixed" node is displaced
 
	
 
	// Warning: length constraint not yet  CORRECTLY implemented for this function
 
	
 
	// Attempt to move this cell in a random direction
 
	//  Vector movement(par.mc_cell_stepsize*(RANDOM()-0.5),par.mc_cell_stepsize*(RANDOM()-0.5),0);
 
	
 
	
 
	dh=0;
 
	
 
	Vector movement(dx,dy,0);
 
	
 
	vector< pair<Node *, Node *> > length_edges;
 
	vector<double> cellareas;
 
	cellareas.reserve(neighbors.size());
 
	
 
	// for the length constraint, collect all edges to this cell's nodes,
 
	// which are not part of the cell
 
	// the length of these edges will change
 
	
 
	double old_length=0.;
 
	for (list<Node *>::const_iterator i=nodes.begin();
 
		 i!=nodes.end();
 
		 i++) {
 
		
 
double Cell::Displace(double dx, double dy, double dh)
 
{
 

	
 
  // Displace whole cell, add resulting energy to dh,
 
  // and accept displacement if energetically favorable
 
  // 
 
  // Method is called if a "fixed" node is displaced
 

	
 
  // Warning: length constraint not yet  CORRECTLY implemented for this function
 

	
 
  // Attempt to move this cell in a random direction
 
  //  Vector movement(par.mc_cell_stepsize*(RANDOM()-0.5),par.mc_cell_stepsize*(RANDOM()-0.5),0);
 

	
 

	
 
  dh=0;
 

	
 
  Vector movement(dx,dy,0);
 

	
 
  vector< pair<Node *, Node *> > length_edges;
 
  vector<double> cellareas;
 
  cellareas.reserve(neighbors.size());
 

	
 
  // for the length constraint, collect all edges to this cell's nodes,
 
  // which are not part of the cell
 
  // the length of these edges will change
 

	
 
  double old_length=0.;
 
  for (list<Node *>::const_iterator i=nodes.begin();
 
       i!=nodes.end();
 
       i++) {
 

	
 

	
 
    for (list<Neighbor>::const_iterator n=(*i)->owners.begin();
 
	 n!=(*i)->owners.end();
 
	 n++) {
 

	
 
      if (n->getCell()!=this) {
 
	length_edges.push_back( pair <Node *,Node *> (*i, n->nb1) );
 
	length_edges.push_back( pair <Node *,Node *> (*i, n->nb2) );
 
	old_length += 
 
	  DSQR(Node::target_length-(*(*i)-*(n->nb1)).Norm())+
 
	  DSQR(Node::target_length-(*(*i)-*(n->nb2)).Norm());
 
      }
 
    }
 
  }
 

	
 
		for (list<Neighbor>::const_iterator n=(*i)->owners.begin();
 
			 n!=(*i)->owners.end();
 
			 n++) {
 
			
 
			if (n->getCell()!=this) {
 
				length_edges.push_back( pair <Node *,Node *> (*i, n->nb1) );
 
				length_edges.push_back( pair <Node *,Node *> (*i, n->nb2) );
 
				old_length += 
 
				DSQR(Node::target_length-(*(*i)-*(n->nb1)).Norm())+
 
				DSQR(Node::target_length-(*(*i)-*(n->nb2)).Norm());
 
			}
 
		}
 
	}
 
	
 
	// calculate area energy difference of neighboring cells
 
	// (this cells' shape remains unchanged)
 
	double old_area_energy=0., old_length_energy=0.;
 
	for (list<CellBase *>::const_iterator i=neighbors.begin();
 
		 i!=neighbors.end();
 
		 i++) {
 
		old_area_energy += DSQR((*i)->Area()-(*i)->TargetArea());
 
		old_length_energy += DSQR((*i)->Length()-(*i)->TargetLength());
 
	}
 
	
 
	Move(movement);
 
	
 
	double new_area_energy=0., new_length_energy=0.;
 
	for (list<CellBase *>::const_iterator i=neighbors.begin();
 
		 i!=neighbors.end();
 
		 i++) {
 
		cellareas.push_back((*i)->CalcArea());
 
		new_area_energy += DSQR(cellareas.back()-(*i)->TargetArea());
 
		new_length_energy += DSQR((*i)->CalcLength()-(*i)->TargetLength());
 
	}
 
	
 
	double new_length=0;
 
	for ( vector< pair< Node *, Node * > >::const_iterator e = length_edges.begin();
 
		 e != length_edges.end();
 
		 e++) {
 
		new_length +=  DSQR(Node::target_length-
 
							(*(e->first)-*(e->second)).Norm());
 
	}
 
	
 
	
 
	dh += (new_area_energy - old_area_energy) + (new_length_energy - old_length_energy) * lambda_celllength +
 
	par.lambda_length * (new_length - old_length);
 
	
 
	if (dh<0 || RANDOM()<exp(-dh/par.T)) {
 
		
 
		// update areas of cells
 
		//cerr << "neighbors: ";
 
		list<CellBase *>::const_iterator nb_it = neighbors.begin();
 
		for (vector<double>::const_iterator ar_it = cellareas.begin();
 
			 ar_it!=cellareas.end();
 
			 ( ar_it++, nb_it++) ) {
 
			((Cell *)(*nb_it))->area = *ar_it;
 
			(*nb_it)->SetIntegrals(); 
 
		}
 
		
 
		//cerr << endl;
 
		
 
	} else {
 
		
 
		Move ( -1*movement);
 
		
 
	}
 
	
 
	return dh;
 
  // calculate area energy difference of neighboring cells
 
  // (this cells' shape remains unchanged)
 
  double old_area_energy=0., old_length_energy=0.;
 
  for (list<CellBase *>::const_iterator i=neighbors.begin();
 
       i!=neighbors.end();
 
       i++) {
 
    old_area_energy += DSQR((*i)->Area()-(*i)->TargetArea());
 
    old_length_energy += DSQR((*i)->Length()-(*i)->TargetLength());
 
  }
 

	
 
  Move(movement);
 

	
 
  double new_area_energy=0., new_length_energy=0.;
 
  for (list<CellBase *>::const_iterator i=neighbors.begin();
 
       i!=neighbors.end();
 
       i++) {
 
    cellareas.push_back((*i)->CalcArea());
 
    new_area_energy += DSQR(cellareas.back()-(*i)->TargetArea());
 
    new_length_energy += DSQR((*i)->CalcLength()-(*i)->TargetLength());
 
  }
 

	
 
  double new_length=0;
 
  for ( vector< pair< Node *, Node * > >::const_iterator e = length_edges.begin();
 
	e != length_edges.end();
 
	e++) {
 
    new_length +=  DSQR(Node::target_length-
 
			(*(e->first)-*(e->second)).Norm());
 
  }
 

	
 

	
 
  dh += (new_area_energy - old_area_energy) + (new_length_energy - old_length_energy) * lambda_celllength +
 
    par.lambda_length * (new_length - old_length);
 

	
 
  if (dh<0 || RANDOM()<exp(-dh/par.T)) {
 

	
 
    // update areas of cells
 
    //cerr << "neighbors: ";
 
    list<CellBase *>::const_iterator nb_it = neighbors.begin();
 
    for (vector<double>::const_iterator ar_it = cellareas.begin();
 
	 ar_it!=cellareas.end();
 
	 ( ar_it++, nb_it++) ) {
 
      ((Cell *)(*nb_it))->area = *ar_it;
 
      (*nb_it)->SetIntegrals(); 
 
    }
 

	
 
    //cerr << endl;
 

	
 
  } else {
 

	
 
    Move ( -1*movement);
 

	
 
  }
 

	
 
  return dh;
 
}
 

	
 

	
 
void Cell::Displace (void) {
 
	Displace(par.mc_cell_stepsize*(RANDOM()-0.5),par.mc_cell_stepsize*(RANDOM()-0.5),0);
 
void Cell::Displace (void)
 
{
 
  Displace(par.mc_cell_stepsize*(RANDOM()-0.5),par.mc_cell_stepsize*(RANDOM()-0.5),0);
 
}
 

	
 
// Get energy level of whole cell (excluding length constraint?)
 
double Cell::Energy(void) const {
 
	
 
	double energy = 0.;
 
	double length_contribution = 0.;
 
	
 
	for (list<Node *>::const_iterator i=nodes.begin();
 
		 i!=nodes.end();
 
		 i++) {
 
		
 
		for (list<Neighbor>::const_iterator n=(*i)->owners.begin();
 
			 n!=(*i)->owners.end();
 
			 n++) {
 
			
 
			if (n->getCell()==this) {
 
				
 
				length_contribution += 
 
				DSQR(Node::target_length-(*(*i)-*(n->nb1)).Norm())+
 
				DSQR(Node::target_length-(*(*i)-*(n->nb2)).Norm());
 
				
 
			}
 
		}
 
	}
 
	
 
	// wall elasticity constraint
 
	energy += par.lambda_length * length_contribution;
 
	
 
	// area constraint
 
	energy += DSQR(CalcArea() - target_area);
 
	
 
	// cell length constraint
 
	
 
	
 
	energy += lambda_celllength * DSQR(Length() - target_length);
 
	
 
	
 
	return energy;
 
double Cell::Energy(void) const
 
{
 
  double energy = 0.;
 
  double length_contribution = 0.;
 

	
 
  for (list<Node *>::const_iterator i=nodes.begin();
 
       i!=nodes.end();
 
       i++) {
 

	
 
    for (list<Neighbor>::const_iterator n=(*i)->owners.begin();
 
	 n!=(*i)->owners.end();
 
	 n++) {
 

	
 
      if (n->getCell()==this) {
 

	
 
	length_contribution += 
 
	  DSQR(Node::target_length-(*(*i)-*(n->nb1)).Norm())+
 
	  DSQR(Node::target_length-(*(*i)-*(n->nb2)).Norm());
 

	
 
      }
 
    }
 
  }
 

	
 
  // wall elasticity constraint
 
  energy += par.lambda_length * length_contribution;
 

	
 
  // area constraint
 
  energy += DSQR(CalcArea() - target_area);
 

	
 
  // cell length constraint
 
  energy += lambda_celllength * DSQR(Length() - target_length);
 

	
 
  return energy;
 
}
 

	
 

	
 

	
 

	
 

	
 
bool Cell::SelfIntersect(void) {
 
	
 
    // The (obvious) O(N*N) algorithm
 
	
 
    // Compare each edge against each other edge
 
	
 
    // An O(N log(N)) algorithm by Shamos & Hoey (1976) supposedly exists;
 
    // it was mentioned on comp.graphics.algorithms
 
	
 
    // But I haven't been able to lay my hand on the paper.
 
    // Let's try whether we need it....
 
	
 
    // method used: http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/
 
bool Cell::SelfIntersect(void)
 
{
 
  // The (obvious) O(N*N) algorithm
 

	
 
  // Compare each edge against each other edge
 

	
 
  // An O(N log(N)) algorithm by Shamos & Hoey (1976) supposedly exists;
 
  // it was mentioned on comp.graphics.algorithms
 

	
 
  // But I haven't been able to lay my hand on the paper.
 
  // Let's try whether we need it....
 

	
 
  // method used: http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/
 

	
 
  for (list<Node *>::const_iterator i=nodes.begin();
 
       i!=nodes.end();
 
       i++) {
 

	
 
    list<Node *>::const_iterator j=i; 
 
    ++j;
 
    for (;
 
	 j!=nodes.end();
 
	 j++) 
 
      {
 
	
 
    for (list<Node *>::const_iterator i=nodes.begin();
 
		 i!=nodes.end();
 
		 i++) {
 
		
 
		list<Node *>::const_iterator j=i; 
 
		++j;
 
		for (;
 
			 j!=nodes.end();
 
			 j++) 
 
		{
 
			
 
			Vector v1 = *(*i);
 
			list<Node *>::const_iterator nb=i;
 
			nb++;
 
			if (nb == nodes.end()) {
 
				nb = nodes.begin();
 
			} 
 
			Vector v2 = *(*nb);
 
			Vector v3 = *(*j);
 
			nb=j;
 
			nb++;
 
			if (nb == nodes.end()) {
 
				nb = nodes.begin();
 
			} 
 
			Vector v4=*( *nb ); 
 
			
 
			double denominator = 
 
			(v4.y - v3.y)*(v2.x - v1.x) - (v4.x - v3.x)*(v2.y - v1.y);
 
			
 
			double ua = 
 
			((v4.x - v3.x)*(v1.y - v3.y) - (v4.y - v3.y)*(v1.x -v3.x))/denominator;
 
			double ub = 
 
			((v2.x - v1.x)*(v1.y-v3.y) - (v2.y- v1.y)*(v1.x - v3.x))/denominator;
 
			
 
			
 
			if ( ( TINY < ua && ua < 1.-TINY ) && ( TINY < ub && ub < 1.-TINY ) ) {
 
				//cerr << "ua = " << ua << ", ub = " << ub << endl;
 
				return true;
 
			}
 
		}
 
    }
 
	
 
    return false;
 
	Vector v1 = *(*i);
 
	list<Node *>::const_iterator nb=i;
 
	nb++;
 
	if (nb == nodes.end()) {
 
	  nb = nodes.begin();
 
	} 
 
	Vector v2 = *(*nb);
 
	Vector v3 = *(*j);
 
	nb=j;
 
	nb++;
 
	if (nb == nodes.end()) {
 
	  nb = nodes.begin();
 
	} 
 
	Vector v4=*( *nb ); 
 

	
 
	double denominator = 
 
	  (v4.y - v3.y)*(v2.x - v1.x) - (v4.x - v3.x)*(v2.y - v1.y);
 

	
 
	double ua = 
 
	  ((v4.x - v3.x)*(v1.y - v3.y) - (v4.y - v3.y)*(v1.x -v3.x))/denominator;
 
	double ub = 
 
	  ((v2.x - v1.x)*(v1.y-v3.y) - (v2.y- v1.y)*(v1.x - v3.x))/denominator;
 

	
 

	
 
	if ( ( TINY < ua && ua < 1.-TINY ) && ( TINY < ub && ub < 1.-TINY ) ) {
 
	  //cerr << "ua = " << ua << ", ub = " << ub << endl;
 
	  return true;
 
	}
 
      }
 
  }
 

	
 
  return false;
 
}
 

	
 

	
 
bool Cell::MoveSelfIntersectsP(Node *moving_node_ind, Vector new_pos) {
 
	
 
	// Check whether the polygon will self-intersect if moving_node_ind 
 
	// were displaced to new_pos
 
	
 
	// Compare the two new edges against each other edge
 
	
 
	// O(2*N)
 
	
 
	// method used for segment intersection:
 
	// http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/
 
	
 
	Vector neighbor_of_moving_node[2];
 
	
 
	//cerr << "list<Node *>::const_iterator moving_node_ind_pos = find (nodes.begin(),nodes.end(),moving_node_ind);\n";
 
	list<Node *>::const_iterator moving_node_ind_pos = find (nodes.begin(),nodes.end(),moving_node_ind);
 
	
 
	list<Node *>::const_iterator nb = moving_node_ind_pos;
 
	//cerr << "Done\n";
 
	nb++;
 
	if (nb == nodes.end()) {
 
		nb = nodes.begin();
 
	} 
 
	
 
	neighbor_of_moving_node[0]=*(*nb); 
 
	
 
	nb=moving_node_ind_pos;
 
	if (nb == nodes.begin()) {
 
		nb = nodes.end();
 
	}
 
	nb--;
 
	
 
	neighbor_of_moving_node[1]=*( *nb ); 
 
	
 
	
 
	for (list<Node *>::const_iterator i=nodes.begin();
 
		 i!=nodes.end();
 
		 i++) {
 
		
 
		for (int j=0;j<2;j++) { // loop over the two neighbors of moving node
 
			list<Node *>::const_iterator nb=i;
 
			nb++;
 
			if (nb == nodes.end()) {
 
				nb = nodes.begin();
 
			} 
 
			if (*i == moving_node_ind || *nb == moving_node_ind) {
 
				// do not compare to self
 
				continue;
 
			}
 
			
 
			Vector v3 = *(*i);
 
			Vector v4 = *(*nb);
 
			
 
			double denominator = 
 
			(v4.y - v3.y)*(neighbor_of_moving_node[j].x - new_pos.x) - (v4.x - v3.x)*(neighbor_of_moving_node[j].y - new_pos.y);
 
			
 
			double ua = 
 
			((v4.x - v3.x)*(new_pos.y - v3.y) - (v4.y - v3.y)*(new_pos.x -v3.x))/denominator;
 
			double ub = 
 
			((neighbor_of_moving_node[j].x - new_pos.x)*(new_pos.y-v3.y) - (neighbor_of_moving_node[j].y- new_pos.y)*(new_pos.x - v3.x))/denominator;
 
			
 
			if ( ( TINY < ua && ua < 1.-TINY ) && ( TINY < ub && ub < 1.-TINY ) ) {
 
				//cerr << "ua = " << ua << ", ub = " << ub << endl;
 
				return true;
 
			}
 
		}
 
	}
 
	
 
	return false;
 
bool Cell::MoveSelfIntersectsP(Node *moving_node_ind, Vector new_pos)
 
{
 

	
 
  // Check whether the polygon will self-intersect if moving_node_ind 
 
  // were displaced to new_pos
 

	
 
  // Compare the two new edges against each other edge
 

	
 
  // O(2*N)
 

	
 
  // method used for segment intersection:
 
  // http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/
 

	
 
  Vector neighbor_of_moving_node[2];
 

	
 
  //cerr << "list<Node *>::const_iterator moving_node_ind_pos = find (nodes.begin(),nodes.end(),moving_node_ind);\n";
 
  list<Node *>::const_iterator moving_node_ind_pos = find (nodes.begin(),nodes.end(),moving_node_ind);
 

	
 
  list<Node *>::const_iterator nb = moving_node_ind_pos;
 
  //cerr << "Done\n";
 
  nb++;
 
  if (nb == nodes.end()) {
 
    nb = nodes.begin();
 
  } 
 

	
 
  neighbor_of_moving_node[0]=*(*nb); 
 

	
 
  nb=moving_node_ind_pos;
 
  if (nb == nodes.begin()) {
 
    nb = nodes.end();
 
  }
 
  nb--;
 

	
 
  neighbor_of_moving_node[1]=*( *nb ); 
 

	
 

	
 
  for (list<Node *>::const_iterator i=nodes.begin();
 
       i!=nodes.end();
 
       i++) {
 

	
 
    for (int j=0;j<2;j++) { // loop over the two neighbors of moving node
 
      list<Node *>::const_iterator nb=i;
 
      nb++;
 
      if (nb == nodes.end()) {
 
	nb = nodes.begin();
 
      } 
 
      if (*i == moving_node_ind || *nb == moving_node_ind) {
 
	// do not compare to self
 
	continue;
 
      }
 

	
 
      Vector v3 = *(*i);
 
      Vector v4 = *(*nb);
 

	
 
      double denominator = 
 
	(v4.y - v3.y)*(neighbor_of_moving_node[j].x - new_pos.x) - (v4.x - v3.x)*(neighbor_of_moving_node[j].y - new_pos.y);
 

	
 
      double ua = 
 
	((v4.x - v3.x)*(new_pos.y - v3.y) - (v4.y - v3.y)*(new_pos.x -v3.x))/denominator;
 
      double ub = 
 
	((neighbor_of_moving_node[j].x - new_pos.x)*(new_pos.y-v3.y) - (neighbor_of_moving_node[j].y- new_pos.y)*(new_pos.x - v3.x))/denominator;
 

	
 
      if ( ( TINY < ua && ua < 1.-TINY ) && ( TINY < ub && ub < 1.-TINY ) ) {
 
	//cerr << "ua = " << ua << ", ub = " << ub << endl;
 
	return true;
 
      }
 
    }
 
  }
 
  return false;
 
}
 

	
 
/*! \brief Test if this cell intersects with the given line.
 
 
 

	
 
 */
 
bool Cell::IntersectsWithLineP(const Vector v1, const Vector v2) {
 
	
 
	
 
	// Compare the line against each edge
 
	
 
	// method used: http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/
 
	
 
	
 
	
 
	for (list<Node *>::const_iterator i=nodes.begin();
 
		 i!=nodes.end();
 
		 i++) 
 
bool Cell::IntersectsWithLineP(const Vector v1, const Vector v2)
 
{
 
  // Compare the line against each edge
 
  // method used: http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/
 

	
 
  for (list<Node *>::const_iterator i=nodes.begin(); i!=nodes.end(); i++) 
 
    {
 
		
 
		Vector v3 = *(*i);
 
		list<Node *>::const_iterator nb=i;
 
		nb++;
 
		if (nb == nodes.end()) {
 
			nb = nodes.begin();
 
		}
 
		Vector v4 = *(*nb);
 
		
 
		double denominator = 
 
		(v4.y - v3.y)*(v2.x - v1.x) - (v4.x - v3.x)*(v2.y - v1.y);
 
		
 
		double ua = 
 
		((v4.x - v3.x)*(v1.y - v3.y) - (v4.y - v3.y)*(v1.x -v3.x))/denominator;
 
		double ub = 
 
		((v2.x - v1.x)*(v1.y-v3.y) - (v2.y- v1.y)*(v1.x - v3.x))/denominator;
 
		
 
		if ( ( TINY < ua && ua < 1.-TINY ) && ( TINY < ub && ub < 1.-TINY ) ) {
 
			return true;
 
		}
 
      Vector v3 = *(*i);
 
      list<Node *>::const_iterator nb=i;
 
      nb++;
 
      if (nb == nodes.end()) {
 
	nb = nodes.begin();
 
      }
 
      Vector v4 = *(*nb);
 

	
 
      double denominator = 
 
	(v4.y - v3.y)*(v2.x - v1.x) - (v4.x - v3.x)*(v2.y - v1.y);
 

	
 
      double ua = 
 
	((v4.x - v3.x)*(v1.y - v3.y) - (v4.y - v3.y)*(v1.x -v3.x))/denominator;
 
      double ub = 
 
	((v2.x - v1.x)*(v1.y-v3.y) - (v2.y- v1.y)*(v1.x - v3.x))/denominator;
 

	
 
      if ( ( TINY < ua && ua < 1.-TINY ) && ( TINY < ub && ub < 1.-TINY ) ) {
 
	return true;
 
      }
 
    }
 
	
 
	return false;
 
	
 
	
 
  return false;
 
}
 
/*! \brief Constructs Walls, but only one per cell boundary.
 
 
 
 Standard method constructs a Wall for each cell wall element,
 
 making transport algorithms computationally more intensive than needed.
 
 
 
 We can remove this? Well, let's leave it in the code in case we need it for something else. E.g. for importing leaf architectures in different formats than our own... :-)
 
 
 
 */
 
void Cell::ConstructWalls(void) {
 
	
 

	
 
  Standard method constructs a Wall for each cell wall element,
 
  making transport algorithms computationally more intensive than needed.
 

	
 
  We can remove this? Well, let's leave it in the code in case we need it for something else. E.g. for importing leaf architectures in different formats than our own... :-)
 

	
 
*/
 
void Cell::ConstructWalls(void)
 
{
 
  return;
 
  if (dead) return;
 

	
 
  walls.clear();
 
  neighbors.clear();
 

	
 
  // Get "corner points; i.e. nodes where more than 2 cells are connected
 
  list<Node *> corner_points;
 

	
 
  for (list<Node *>::const_iterator i=nodes.begin();
 
       i!=nodes.end();i++) {
 

	
 
    // look for nodes belonging to >2 cells
 
    if ((*i)->owners.size()>2) {
 

	
 
      // push onto list
 
      corner_points.push_back(*i);
 
    }
 
  }
 

	
 
  // Construct Walls between corner points
 

	
 
  // previous one in list
 
  list<Node *>::const_iterator nb = (--corner_points.end());
 

	
 
  // loop over list, 
 
  for (list<Node *>::const_iterator i=corner_points.begin();
 
       i!=corner_points.end(); ( i++, nb++) ) {
 

	
 
    if (nb==corner_points.end()) nb=corner_points.begin();
 
    // add owning cells to a list
 
    list<Cell *> owning_cells;
 
    Node &n(*(*i));
 

	
 
    for (list<Neighbor>::const_iterator j=n.owners.begin();
 
	 j!=n.owners.end();
 
	 j++) {
 
      owning_cells.push_back(j->cell);
 
    }
 

	
 
    Node &n2(*(*nb));
 
    for (list<Neighbor>::const_iterator j=n2.owners.begin();
 
	 j!=n2.owners.end();
 
	 j++) {
 
      owning_cells.push_back(j->cell);
 
    }
 

	
 
    // sort cell owners
 
    owning_cells.sort( mem_fun( &Cell::Cmp ));
 

	
 
    // find duplicates
 
    vector<Cell *> duplicates;
 
    list<Cell *>::const_iterator prevj = (--owning_cells.end());
 
    for (list<Cell *>::const_iterator j=owning_cells.begin();
 
	 j!=owning_cells.end();
 
	 ( j++, prevj++) ) {
 

	
 
      if (prevj==owning_cells.end()) prevj=owning_cells.begin();
 
      if (*j==*prevj) duplicates.push_back(*j);
 

	
 
    }
 

	
 

	
 
    if (duplicates.size()==3) { // ignore cell boundary (this occurs only after the first division, I think)
 
      vector<Cell *>::iterator dup_it = find_if(duplicates.begin(),duplicates.end(),mem_fun(&Cell::BoundaryPolP) );
 
      if (dup_it!=duplicates.end()) 
 
	duplicates.erase(dup_it);
 
      else {
 
	return;
 
	if (dead) return;
 
	
 
	walls.clear();
 
	neighbors.clear();
 
	
 
	// Get "corner points; i.e. nodes where more than 2 cells are connected
 
	list<Node *> corner_points;
 
	
 
	for (list<Node *>::const_iterator i=nodes.begin();
 
		 i!=nodes.end();i++) {
 
		
 
		// look for nodes belonging to >2 cells
 
		if ((*i)->owners.size()>2) {
 
			
 
			// push onto list
 
			corner_points.push_back(*i);
 
		}
 
		
 
	}
 
	
 
	// Construct Walls between corner points
 
	
 
	// previous one in list
 
	list<Node *>::const_iterator nb = (--corner_points.end());
 
	
 
	// loop over list, 
 
	for (list<Node *>::const_iterator i=corner_points.begin();
 
		 i!=corner_points.end(); ( i++, nb++) ) {
 
		
 
		if (nb==corner_points.end()) nb=corner_points.begin();
 
		// add owning cells to a list
 
		list<Cell *> owning_cells;
 
		Node &n(*(*i));
 
		
 
		for (list<Neighbor>::const_iterator j=n.owners.begin();
 
			 j!=n.owners.end();
 
			 j++) {
 
			owning_cells.push_back(j->cell);
 
		}
 
		
 
		Node &n2(*(*nb));
 
		for (list<Neighbor>::const_iterator j=n2.owners.begin();
 
			 j!=n2.owners.end();
 
			 j++) {
 
			owning_cells.push_back(j->cell);
 
		}
 
		
 
		// sort cell owners
 
		owning_cells.sort( mem_fun( &Cell::Cmp ));
 
      }
 
    }
 

	
 

	
 
    // One Wall for each neighbor, so we should be able to correctly construct neighbor lists here.
 
    if (duplicates[0]==this) {
 
      AddWall(  new Wall(*nb,*i,duplicates[0],duplicates[1]) );
 
      if (!duplicates[1]->BoundaryPolP()) {
 

	
 
		// find duplicates
 
		vector<Cell *> duplicates;
 
		list<Cell *>::const_iterator prevj = (--owning_cells.end());
 
		for (list<Cell *>::const_iterator j=owning_cells.begin();
 
			 j!=owning_cells.end();
 
			 ( j++, prevj++) ) {
 
			
 
			if (prevj==owning_cells.end()) prevj=owning_cells.begin();
 
			if (*j==*prevj) duplicates.push_back(*j);
 
			
 
		}
 
		
 
		
 
		if (duplicates.size()==3) { // ignore cell boundary (this occurs only after the first division, I think)
 
			vector<Cell *>::iterator dup_it = find_if(duplicates.begin(),duplicates.end(),mem_fun(&Cell::BoundaryPolP) );
 
			if (dup_it!=duplicates.end()) 
 
				duplicates.erase(dup_it);
 
			else {
 
				return;
 
			}
 
			
 
		}
 
		
 
		
 
		// One Wall for each neighbor, so we should be able to correctly construct neighbor lists here.
 
		if (duplicates[0]==this) {
 
			AddWall(  new Wall(*nb,*i,duplicates[0],duplicates[1]) );
 
			if (!duplicates[1]->BoundaryPolP()) {
 
				
 
				neighbors.push_back(duplicates[1]);
 
			}
 
		} else {
 
			AddWall ( new Wall(*nb,*i,duplicates[1],duplicates[0]) );
 
			if (!duplicates[0]->BoundaryPolP()) {
 
				neighbors.push_back(duplicates[0]);
 
				
 
			}
 
		}
 
	}
 
	
 
	neighbors.push_back(duplicates[1]);
 
      }
 
    } else {
 
      AddWall ( new Wall(*nb,*i,duplicates[1],duplicates[0]) );
 
      if (!duplicates[0]->BoundaryPolP()) {
 
	neighbors.push_back(duplicates[0]);
 

	
 
      }
 
    }
 
  }
 
}
 

	
 

	
 
void BoundaryPolygon::Draw(QGraphicsScene *c, QString tooltip) {
 
	
 
	// Draw the BoundaryPolygon on a QCanvas object
 
	
 
	
 
	CellItem* p = new CellItem(this, c);
 
	
 
	QPolygonF pa(nodes.size());
 
	int cc=0;
 
	
 
	for (list<Node *>::const_iterator n=nodes.begin();
 
		 n!=nodes.end();
 
		 n++) {
 
		Node *i=*n;
 
		
 
		pa[cc++] = QPoint((int)((Offset().x+i->x)*Factor()),
 
						  (int)((Offset().y+i->y)*Factor()) );
 
	}
 
	
 
	
 
	p->setPolygon(pa);
 
	p->setPen(par.outlinewidth>=0?QPen( QColor(par.cell_outline_color),par.outlinewidth):QPen(Qt::NoPen));
 
	p->setBrush( Qt::NoBrush );
 
	p->setZValue(1);
 
	
 
	if (!tooltip.isEmpty())
 
		p->setToolTip(tooltip);
 
	
 
	p->show();
 
	
 
void BoundaryPolygon::Draw(QGraphicsScene *c, QString tooltip)
 
{
 

	
 
  // Draw the BoundaryPolygon on a QCanvas object
 

	
 
  CellItem* p = new CellItem(this, c);
 

	
 
  QPolygonF pa(nodes.size());
 
  int cc=0;
 

	
 
  for (list<Node *>::const_iterator n=nodes.begin();
 
       n!=nodes.end();
 
       n++) {
 
    Node *i=*n;
 

	
 
    pa[cc++] = QPoint((int)((Offset().x+i->x)*Factor()),
 
		      (int)((Offset().y+i->y)*Factor()) );
 
  }
 

	
 
  p->setPolygon(pa);
 
  p->setPen(par.outlinewidth>=0?QPen( QColor(par.cell_outline_color),par.outlinewidth):QPen(Qt::NoPen));
 
  p->setBrush( Qt::NoBrush );
 
  p->setZValue(1);
 

	
 
  if (!tooltip.isEmpty())
 
    p->setToolTip(tooltip);
 

	
 
  p->show();
 
}
 

	
 
void Cell::Flux(double *flux, double *D)  {
 
	
 
	
 
	// loop over cell edges
 
	
 
	for (int c=0;c<NChem();c++) flux[c]=0.;
 
	
 
	for (list<Wall *>::iterator i=walls.begin();
 
		 i!=walls.end();
 
		 i++) {
 
		
 
		
 
		// leaf cannot take up chemicals from environment ("no flux boundary")
 
		if ((*i)->c2->BoundaryPolP()) continue;
 
		
 
		
 
		// flux depends on edge length and concentration difference
 
		for (int c=0;c<NChem();c++) {
 
			double phi = (*i)->length * ( D[c] ) * ( ((Cell *)(*i)->c2)->chem[c] - chem[c] );
 
			
 
			#ifdef QDEBUG
 
			if ((*i)->c1!=this) {
 
			  qDebug() << "Warning, bad cells boundary: " << (*i)->c1->Index() << ", " << index << endl;
 
			}
 
			#endif
 
			
 
			flux[c] += phi;
 
		}    
 
	}
 
	
 
void Cell::Flux(double *flux, double *D)
 
{
 
  // loop over cell edges
 

	
 
  for (int c=0;c<NChem();c++) flux[c]=0.;
 

	
 
  for (list<Wall *>::iterator i=walls.begin();
 
       i!=walls.end();
 
       i++) {
 

	
 

	
 
    // leaf cannot take up chemicals from environment ("no flux boundary")
 
    if ((*i)->c2->BoundaryPolP()) continue;
 

	
 

	
 
    // flux depends on edge length and concentration difference
 
    for (int c=0;c<NChem();c++) {
 
      double phi = (*i)->length * ( D[c] ) * ( ((Cell *)(*i)->c2)->chem[c] - chem[c] );
 

	
 
#ifdef QDEBUG
 
      if ((*i)->c1!=this) {
 
	qDebug() << "Warning, bad cells boundary: " << (*i)->c1->Index() << ", " << index << endl;
 
      }
 
#endif
 

	
 
      flux[c] += phi;
 
    }    
 
  }
 
}
 

	
 

	
 
// graphics stuff, not compiled for batch versions
 
#ifdef QTGRAPHICS
 

	
 
#include "canvas.h"
 

	
 
void Cell::Draw(QGraphicsScene *c, QString tooltip) {
 
	
 
	// Draw the cell on a QCanvas object
 
	
 
	if (DeadP()) { 
 
	        #ifdef QDEBUG
 
	  qDebug() << "Cell " << index << " not drawn, because dead." << endl;
 
		#endif
 
		return;
 
	}
 
	
 
	CellItem* p = new CellItem(this, c);
 
	
 
	QPolygonF pa(nodes.size());
 
	int cc=0;
 
	
 
	for (list<Node *>::const_iterator n=nodes.begin();
 
		 n!=nodes.end();
 
		 n++) {
 
		Node *i=*n;
 
		
 
		pa[cc++] = QPoint((int)((offset[0]+i->x)*factor),
 
						  (int)((offset[1]+i->y)*factor) );
 
	}
 
	
 
	
 
	QColor cell_color;
 
	
 
	m->plugin->SetCellColor(this,&cell_color);
 
	
 
	p->setPolygon(pa);
 
	p->setPen(par.outlinewidth>=0?QPen( QColor(par.cell_outline_color),par.outlinewidth):QPen(Qt::NoPen));
 
	p->setBrush( cell_color );
 
	p->setZValue(1);
 
	
 
	if (!tooltip.isEmpty())
 
		p->setToolTip(tooltip);
 
	
 
	p->show();
 
	
 
void Cell::Draw(QGraphicsScene *c, QString tooltip)
 
{
 

	
 
  // Draw the cell on a QCanvas object
 

	
 
  if (DeadP()) { 
 
#ifdef QDEBUG
 
    qDebug() << "Cell " << index << " not drawn, because dead." << endl;
 
#endif
 
    return;
 
  }
 

	
 
  CellItem* p = new CellItem(this, c);
 

	
 
  QPolygonF pa(nodes.size());
 
  int cc=0;
 

	
 
  for (list<Node *>::const_iterator n=nodes.begin();
 
       n!=nodes.end();
 
       n++) {
 
    Node *i=*n;
 

	
 
    pa[cc++] = QPoint((int)((offset[0]+i->x)*factor),
 
		      (int)((offset[1]+i->y)*factor) );
 
  }
 

	
 

	
 
  QColor cell_color;
 

	
 
  m->plugin->SetCellColor(this,&cell_color);
 

	
 
  p->setPolygon(pa);
 
  p->setPen(par.outlinewidth>=0?QPen( QColor(par.cell_outline_color),par.outlinewidth):QPen(Qt::NoPen));
 
  p->setBrush( cell_color );
 
  p->setZValue(1);
 

	
 
  if (!tooltip.isEmpty())
 
    p->setToolTip(tooltip);
 

	
 
  p->show();
 
}
 

	
 

	
 
void Cell::DrawCenter(QGraphicsScene *c) const {
 
  // Maginfication derived similarly to that in nodeitem.cpp
 
  // Why not use Cell::Magnification()?
 
  const double mag = par.node_mag;
 
	
 
	// construct an ellipse
 

	
 
  // construct an ellipse
 
  QGraphicsEllipseItem *disk = new QGraphicsEllipseItem ( -1*mag, -1*mag, 2*mag, 2*mag, 0, c );
 
	disk->setBrush( QColor("forest green") );
 
	disk->setZValue(5);
 
	disk->show();
 
	Vector centroid=Centroid();
 
	disk -> setPos((offset[0]+centroid.x)*factor,(offset[1]+centroid.y)*factor);
 
  disk->setBrush( QColor("forest green") );
 
  disk->setZValue(5);
 
  disk->show();
 
  Vector centroid=Centroid();
 
  disk -> setPos((offset[0]+centroid.x)*factor,(offset[1]+centroid.y)*factor);
 
}
 

	
 
void Cell::DrawNodes(QGraphicsScene *c) const {
 
	
 
	for (list<Node *>::const_iterator n=nodes.begin();
 
		 n!=nodes.end();
 
		 n++) {
 
		Node *i=*n;
 
		
 

	
 
  for (list<Node *>::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(((offset[0]+i->x)*factor),
 
					  ((offset[1]+i->y)*factor) );
 
	}
 
	
 
    NodeItem *item = new NodeItem ( &(*i), c );
 
    item->setColor();
 
    item->setZValue(5);
 
    item->show();
 
    item ->setPos(((offset[0]+i->x)*factor),
 
		  ((offset[1]+i->y)*factor) );
 
  }
 
}
 

	
 
void Cell::DrawIndex(QGraphicsScene *c) const {
 
	
 
	DrawText( c, QString("%1").arg(index));
 

	
 
  DrawText( c, QString("%1").arg(index));
 
}
 

	
 
// Draw any text in the cell's center
 
void Cell::DrawText(QGraphicsScene *c, const QString &text) const {
 
    
 
	Vector centroid = Centroid();
 
	QGraphicsSimpleTextItem *ctext = new QGraphicsSimpleTextItem ( text, 0, c );
 
	ctext->setPen( QPen(QColor(par.textcolor)) );
 
	ctext->setZValue(20);
 
	ctext->setFont( QFont( "Helvetica", par.cellnumsize, QFont::Bold) );
 
	ctext->show();
 
	ctext ->setPos(((offset[0]+centroid.x)*factor),
 
				   ((offset[1]+centroid.y)*factor) );
 
	
 

	
 
  Vector centroid = Centroid();
 
  QGraphicsSimpleTextItem *ctext = new QGraphicsSimpleTextItem ( text, 0, c );
 
  ctext->setPen( QPen(QColor(par.textcolor)) );
 
  ctext->setZValue(20);
 
  ctext->setFont( QFont( "Helvetica", par.cellnumsize, QFont::Bold) );
 
  ctext->show();
 
  ctext ->setPos(((offset[0]+centroid.x)*factor),
 
		 ((offset[1]+centroid.y)*factor) );
 
}
 

	
 

	
 
void Cell::DrawAxis(QGraphicsScene *c) const {
 
	
 
	Vector long_axis;
 
	double width;
 
	Length(&long_axis, &width);
 
	
 
	//cerr << "Length is "  << length << endl;
 
	long_axis.Normalise();
 
	Vector short_axis=long_axis.Perp2D();
 
    
 

	
 
  Vector long_axis;
 
  double width;
 
  Length(&long_axis, &width);
 

	
 
  //cerr << "Length is "  << length << endl;
 
  long_axis.Normalise();
 
  Vector short_axis=long_axis.Perp2D();
 

	
 

	
 
	Vector centroid = Centroid();
 
	Vector from = centroid - 0.5 * width * short_axis;
 
	Vector to = centroid + 0.5 * width *short_axis;
 
  Vector centroid = Centroid();
 
  Vector from = centroid - 0.5 * width * short_axis;
 
  Vector to = centroid + 0.5 * width *short_axis;
 

	
 

	
 
	
 
	QGraphicsLineItem *line = new QGraphicsLineItem(0, c);
 
	line->setPen( QPen(QColor(par.arrowcolor),2) );
 
	line->setZValue(2);
 
    
 
	line->setLine( ( (offset[0]+from.x)*factor ),
 
				  ( (offset[1]+from.y)*factor ), 
 
				  ( (offset[0]+to.x)*factor ),
 
				  ( (offset[1]+to.y)*factor ) );
 
	line->setZValue(10);
 
	line->show();
 
	
 
  QGraphicsLineItem *line = new QGraphicsLineItem(0, c);
 
  line->setPen( QPen(QColor(par.arrowcolor),2) );
 
  line->setZValue(2);
 

	
 
  line->setLine( ( (offset[0]+from.x)*factor ),
 
		 ( (offset[1]+from.y)*factor ), 
 
		 ( (offset[0]+to.x)*factor ),
 
		 ( (offset[1]+to.y)*factor ) );
 
  line->setZValue(10);
 
  line->show();
 
}
 

	
 
void Cell::DrawStrain(QGraphicsScene *c) const {
 
  c = NULL; // assignment merely to obviate compilation warning
 
	MyWarning::warning("Sorry, Cell::DrawStrain temporarily not implemented.");
 
  MyWarning::warning("Sorry, Cell::DrawStrain temporarily not implemented.");
 
}
 

	
 

	
 
void Cell::DrawFluxes(QGraphicsScene *c, double arrowsize)  {
 
	
 
	// get the mean flux through this cell
 
	Vector vec_flux = ReduceCellAndWalls<Vector>( PINdir );
 
	
 
	vec_flux.Normalise();
 
	
 
	vec_flux *= arrowsize;
 
	
 
	QGraphicsArrowItem *arrow = new QGraphicsArrowItem(0,c);
 
	
 
	Vector centroid = Centroid();
 
	Vector from = centroid - vec_flux/2.;
 
	Vector to = centroid + vec_flux/2.;
 
    
 
	
 
	arrow->setPen( QPen(QColor(par.arrowcolor),par.outlinewidth));
 
	arrow->setZValue(2);
 
	
 
	arrow->setLine( ( (offset[0]+from.x)*factor ),
 
				   ( (offset[1]+from.y)*factor ), 
 
				   ( (offset[0]+to.x)*factor ),
 
				   ( (offset[1]+to.y)*factor ) );
 
	arrow->setZValue(10);
 
	arrow->show();
 
	
 
void Cell::DrawFluxes(QGraphicsScene *c, double arrowsize)
 
{
 

	
 
  // get the mean flux through this cell
 
  Vector vec_flux = ReduceCellAndWalls<Vector>( PINdir );
 

	
 
  vec_flux.Normalise();
 

	
 
  vec_flux *= arrowsize;
 

	
 
  QGraphicsArrowItem *arrow = new QGraphicsArrowItem(0,c);
 

	
 
  Vector centroid = Centroid();
 
  Vector from = centroid - vec_flux/2.;
 
  Vector to = centroid + vec_flux/2.;
 

	
 

	
 
  arrow->setPen( QPen(QColor(par.arrowcolor),par.outlinewidth));
 
  arrow->setZValue(2);
 

	
 
  arrow->setLine( ( (offset[0]+from.x)*factor ),
 
		  ( (offset[1]+from.y)*factor ), 
 
		  ( (offset[0]+to.x)*factor ),
 
		  ( (offset[1]+to.y)*factor ) );
 
  arrow->setZValue(10);
 
  arrow->show();
 
}
 

	
 

	
 
void Cell::DrawWalls(QGraphicsScene *c) const {
 
	
 
	for_each(walls.begin(), walls.end(), bind2nd ( mem_fun ( &Wall::Draw ) , c ) );
 
	
 
	// to see the cells connected the each wall (for debugging), uncomment the following
 
	//for_each(walls.begin(), walls.end(), bind2nd ( mem_fun ( &Wall::ShowStructure ), c ) );
 

	
 
  for_each(walls.begin(), walls.end(), bind2nd ( mem_fun ( &Wall::Draw ) , c ) );
 

	
 
  // to see the cells connected the each wall (for debugging), uncomment the following
 
  //for_each(walls.begin(), walls.end(), bind2nd ( mem_fun ( &Wall::ShowStructure ), c ) );
 
}
 

	
 

	
 
void Cell::DrawValence(QGraphicsScene *c) const {
 
	
 
	DrawText(c, QString("%1").arg(walls.size()) );
 
	
 

	
 
  DrawText(c, QString("%1").arg(walls.size()) );
 
}
 

	
 
#endif
 
#endif // QTGRAPHICS !
 

	
 
/*! \brief Recalculate the lengths of the cell's Walls.
 
 
 
 Call this function after the Monte Carlo updates, and before doing the reaction-diffusion iterations.
 
 
 
 */
 
void Cell::SetWallLengths(void) {
 
	
 
	for (list<Wall *>::iterator de=walls.begin();
 
		 de!=walls.end();
 
		 de++) {
 
		
 
		// Step 1: find the path of nodes leading along the Wall.
 
		// A Wall often represents a curved cell wall: we want the total
 
		// length _along_ the wall here...
 
		
 
		
 
		// Locate first and second nodes of the edge in list of nodes
 
		list<Node *>::const_iterator first_node_edge = find(nodes.begin(), nodes.end(), (*de)->n1);
 
		list<Node *>::const_iterator second_node_edge_plus_1 = ++find(nodes.begin(), nodes.end(), (*de)->n2);
 
		
 
		double sum_length = 0.;
 
		
 
		// Now, walk to the second node of the edge in the list of nodes
 
		for (list<Node *>::const_iterator n=++first_node_edge;
 
			 n!=second_node_edge_plus_1;
 
			 ++n ) {
 
			
 
			if (n==nodes.end()) n=nodes.begin(); /* wrap around */ 
 
			
 
			
 
			list<Node *>::const_iterator prev_n = n; 
 
			if (prev_n==nodes.begin()) prev_n=nodes.end();
 
			--prev_n;
 
			
 
			
 
			// Note that Node derives from a Vector, so we can do vector calculus as defined in vector.h 
 
			sum_length += (*(*prev_n) - *(*n)).Norm(); 
 
			
 
			//cerr << "Node " << *prev_n << " to " << *n << ", cumulative length = " << sum_length << endl;
 
		}
 
		
 
		// We got the total length of the Wall now, store it:
 
		(*de)->length = sum_length;
 
		
 
		//cerr << endl;
 
		// goto next de
 
	}
 

	
 
  Call this function after the Monte Carlo updates, and before doing the reaction-diffusion iterations.
 

	
 
*/
 
void Cell::SetWallLengths(void)
 
{
 

	
 
  for (list<Wall *>::iterator de=walls.begin();
 
       de!=walls.end();
 
       de++) {
 

	
 
    // Step 1: find the path of nodes leading along the Wall.
 
    // A Wall often represents a curved cell wall: we want the total
 
    // length _along_ the wall here...
 

	
 

	
 
    // Locate first and second nodes of the edge in list of nodes
 
    list<Node *>::const_iterator first_node_edge = find(nodes.begin(), nodes.end(), (*de)->n1);
 
    list<Node *>::const_iterator second_node_edge_plus_1 = ++find(nodes.begin(), nodes.end(), (*de)->n2);
 

	
 
    double sum_length = 0.;
 

	
 
    // Now, walk to the second node of the edge in the list of nodes
 
    for (list<Node *>::const_iterator n=++first_node_edge;
 
	 n!=second_node_edge_plus_1;
 
	 ++n ) {
 

	
 
      if (n==nodes.end()) n=nodes.begin(); /* wrap around */ 
 

	
 

	
 
      list<Node *>::const_iterator prev_n = n; 
 
      if (prev_n==nodes.begin()) prev_n=nodes.end();
 
      --prev_n;
 

	
 

	
 
      // Note that Node derives from a Vector, so we can do vector calculus as defined in vector.h 
 
      sum_length += (*(*prev_n) - *(*n)).Norm(); 
 

	
 
      //cerr << "Node " << *prev_n << " to " << *n << ", cumulative length = " << sum_length << endl;
 
    }
 

	
 
    // We got the total length of the Wall now, store it:
 
    (*de)->length = sum_length;
 

	
 
    //cerr << endl;
 
    // goto next de
 
  }
 
}
 

	
 

	
 
//! Add Wall w to the list of Walls
 
void Cell::AddWall( Wall *w ) {
 
	
 
	// if necessary, we could try later inserting it at the correct position
 
        #ifdef QDEBUG
 
	if (w->c1 == w->c2 ){
 
	  qDebug() << "Wall between identical cells: " << w->c1->Index()<< endl;
 
	}
 
	#endif
 
void Cell::AddWall( Wall *w )
 
{
 

	
 
  // if necessary, we could try later inserting it at the correct position
 
#ifdef QDEBUG
 
  if (w->c1 == w->c2 ){
 
    qDebug() << "Wall between identical cells: " << w->c1->Index()<< endl;
 
  }
 
#endif
 

	
 
	// Add Wall to Cell's list
 
	walls.push_back( w );
 
	
 
	// Add wall to Mesh's list if it isn't there yet
 
	
 
	if (find (
 
			  m->walls.begin(), m->walls.end(),
 
			  w )
 
		== m->walls.end() ) {
 
		m->walls.push_back(w);
 
	}
 
	
 
  // Add Wall to Cell's list
 
  walls.push_back( w );
 

	
 
  // Add wall to Mesh's list if it isn't there yet
 

	
 
  if (find (
 
	    m->walls.begin(), m->walls.end(),
 
	    w )
 
      == m->walls.end() ) {
 
    m->walls.push_back(w);
 
  }
 
}
 

	
 
//! Remove Wall w from the list of Walls
 
list<Wall *>::iterator Cell::RemoveWall( Wall *w ) {
 
	
 
	// remove wall from Mesh's list
 
	m->walls.erase(
 
				   find(
 
						m->walls.begin(), m->walls.end(),
 
						w )
 
				   );
 
	
 
	// remove wall from Cell's list
 
	return 
 
	walls.erase (
 
				 find( 
 
					  walls.begin(), walls.end(),
 
					  w )
 
				 );
 
	
 
list<Wall *>::iterator Cell::RemoveWall( Wall *w )
 
{
 

	
 
  // remove wall from Mesh's list
 
  m->walls.erase(
 
		 find(
 
		      m->walls.begin(), m->walls.end(),
 
		      w )
 
		 );
 

	
 
  // remove wall from Cell's list
 
  return walls.erase (find( walls.begin(), walls.end(), w ));
 
}
 

	
 

	
 
void Cell::EmitValues(double t)
 
{
 

	
 
void Cell::EmitValues(double t) {
 
	
 
	//  cerr << "Attempting to emit " << t << ", " << chem[0] << ", " << chem[1] << endl;
 
	emit ChemMonValue(t, chem);
 
	
 
  //  cerr << "Attempting to emit " << t << ", " << chem[0] << ", " << chem[1] << endl;
 
  emit ChemMonValue(t, chem);
 
}
 

	
 
/* finis */
src/cell.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#ifndef _CELL_H_
 
#define _CELL_H_
 

	
 
#include <list>
 
#include <vector>
 
#include <iostream>
 
#include <QString>
 
#include "vector.h"
 
#include "parameter.h"
 
#include "wall.h"
 
#include "warning.h"
 
#include "cellbase.h"
 
#include "cell.h"
 

	
 
#include <QGraphicsScene>
 
#include <qcolor.h>
 
#include <QObject>
 

	
 
#include <libxml/parser.h>
 
#include <libxml/tree.h>
 
#include <QMouseEvent>
 

	
 
class Cell : public CellBase 
 
{
 
	
 
	Q_OBJECT
 
	friend class Mesh;
 
	friend class FigureEditor;
 

	
 
  Q_OBJECT
 
    friend class Mesh;
 
  friend class FigureEditor;
 

	
 
 public:
 
  Cell(double x, double y, double z = 0.);
 
  Cell(void);
 
  Cell(const Cell &src);
 
  Cell operator=(const Cell &src);
 
  bool Cmp(Cell*) const;
 
  bool Eq(Cell*) const;
 

	
 
  inline bool IndexEquals(int i) { return i == index; }
 

	
 
  static void SetMagnification(const double &magn) {
 
    factor=magn;
 
  }
 
  static Vector Offset(void) {
 
    Vector offs;
 
    offs.x=offset[0];
 
    offs.y=offset[1];
 
    return offs;
 
  }
 

	
 
public:
 
	Cell(double x, double y, double z = 0.);
 
	Cell(void);
 
	Cell(const Cell &src);
 
	Cell operator=(const Cell &src);
 
	bool Cmp(Cell*) const;
 
	bool Eq(Cell*) const;
 
  static void Translate(const double &tx,const double &ty) {
 
    offset[0]+=tx;
 
    offset[1]+=ty;
 
  }
 

	
 
  inline static double Factor(void) {
 
    return factor;
 
  }
 
  static void setOffset(double ox, double oy) {
 
    offset[0]=ox;
 
    offset[1]=oy;
 
  }
 
  static double Magnification(void) {
 
    return factor;
 
  }
 

	
 
  static double Scale(const double scale) {
 
    factor*=scale;
 
    return factor;
 
  }
 

	
 
  void DivideOverAxis(Vector axis); // divide cell over axis
 

	
 
  // divide over the line (if line and cell intersect)
 
  bool DivideOverGivenLine(const Vector v1, const Vector v2, bool wall_fixed = false, NodeSet *node_set = 0);
 

	
 
  void Divide(void) { // Divide cell over short axis
 

	
 
    Vector long_axis; 
 
    Length(&long_axis); 
 
    DivideOverAxis(long_axis.Perp2D()); 
 
  }
 

	
 
	inline bool IndexEquals(int i) { return i == index; }
 
	
 
	static void SetMagnification(const double &magn) {
 
		factor=magn;
 
    }
 
    static Vector Offset(void) {
 
		Vector offs;
 
		offs.x=offset[0];
 
		offs.y=offset[1];
 
		return offs;
 
    }
 
	
 
	static void Translate(const double &tx,const double &ty) {
 
		offset[0]+=tx;
 
		offset[1]+=ty;
 
    }
 
	
 
    inline static double Factor(void) {
 
		return factor;
 
    }
 
    static void setOffset(double ox, double oy) {
 
		offset[0]=ox;
 
		offset[1]=oy;
 
    }
 
    static double Magnification(void) {
 
		return factor;
 
    }
 
	
 
    static double Scale(const double scale) {
 
		factor*=scale;
 
		return factor;
 
    }
 
    
 
    void DivideOverAxis(Vector axis); // divide cell over axis
 
    bool DivideOverGivenLine(const Vector v1, const Vector v2, bool wall_fixed = false, NodeSet *node_set = 0); // divide over the line (if line and cell intersect)
 
	
 
    void Divide(void) { // Divide cell over short axis
 
		
 
		Vector long_axis; 
 
		Length(&long_axis); 
 
		DivideOverAxis(long_axis.Perp2D()); 
 
		
 
    }
 
	
 
	//void CheckForGFDrivenDivision(void);
 
    inline int NNodes(void) const { return nodes.size(); }
 
  	
 
    void Move(Vector T);
 
    void Move(double dx, double dy, double dz=0) {
 
		Move( Vector (dx, dy, dz) );
 
    }
 
	
 
	double Displace(double dx, double dy, double dh);
 
    void Displace(void);
 
    double Energy(void) const;
 
    bool SelfIntersect(void);
 
    bool MoveSelfIntersectsP(Node *nid, Vector new_pos);
 
    bool IntersectsWithLineP(const Vector v1, const Vector v2);
 
  //void CheckForGFDrivenDivision(void);
 
  inline int NNodes(void) const { return nodes.size(); }
 

	
 
  void Move(Vector T);
 
  void Move(double dx, double dy, double dz=0) {
 
    Move( Vector (dx, dy, dz) );
 
  }
 

	
 
  double Displace(double dx, double dy, double dh);
 
  void Displace(void);
 
  double Energy(void) const;
 
  bool SelfIntersect(void);
 
  bool MoveSelfIntersectsP(Node *nid, Vector new_pos);
 
  bool IntersectsWithLineP(const Vector v1, const Vector v2);
 

	
 
  void XMLAdd(xmlNodePtr cells_node) const;
 

	
 
  void ConstructWalls(void);
 
  void Flux(double *flux, double *D);
 

	
 
  void OnClick(QMouseEvent *e);
 
  inline Mesh& getMesh(void) const { return *m; }
 
  double MeanArea(void);
 

	
 
  void Apoptose(void); // Cell kills itself
 
  list<Wall *>::iterator RemoveWall( Wall *w );
 
  void AddWall( Wall *w );
 

	
 
  void Draw(QGraphicsScene *c, QString tooltip = QString::Null());
 

	
 
	void XMLAdd(xmlNodePtr cells_node) const;
 
	
 
	void ConstructWalls(void);
 
	void Flux(double *flux, double *D);
 
	
 
	/*! \brief Method called if a cell is clicked. 
 
	 
 
	 Define this in the end-user code (e.g. meinhardt.cpp).
 
	 
 
	 */
 
    void OnClick(QMouseEvent *e);
 
    inline Mesh& getMesh(void) const { return *m; }
 
	double MeanArea(void);
 
	
 
	void Apoptose(void); // Cell kills itself
 
	list<Wall *>::iterator RemoveWall( Wall *w );
 
    void AddWall( Wall *w );
 
  // Draw a text in the cell's center
 
  void DrawText(QGraphicsScene *c, const QString &text) const;
 
  void DrawIndex(QGraphicsScene *c) const;
 
  void DrawCenter(QGraphicsScene *c) const;
 
  void DrawNodes(QGraphicsScene *c) const;
 

	
 
  void DrawAxis(QGraphicsScene *c) const;
 
  void DrawStrain(QGraphicsScene *c) const;
 
  void DrawFluxes(QGraphicsScene *c, double arrowsize = 1.);
 
  void DrawWalls(QGraphicsScene *c) const;
 
  void DrawValence(QGraphicsScene *c) const;
 
  void EmitValues(double t);
 

	
 
    void Draw(QGraphicsScene *c, QString tooltip = QString::Null());
 
    
 
	// Draw a text in the cell's center
 
    void DrawText(QGraphicsScene *c, const QString &text) const;
 
    void DrawIndex(QGraphicsScene *c) const;
 
    void DrawCenter(QGraphicsScene *c) const;
 
    void DrawNodes(QGraphicsScene *c) const;
 
    
 
	void DrawAxis(QGraphicsScene *c) const;
 
    void DrawStrain(QGraphicsScene *c) const;
 
    void DrawFluxes(QGraphicsScene *c, double arrowsize = 1.);
 
    void DrawWalls(QGraphicsScene *c) const;
 
    void DrawValence(QGraphicsScene *c) const;
 
    void EmitValues(double t);
 
	
 
signals:
 
    void ChemMonValue(double t, double *x);
 
	
 
	
 
protected:
 
	void XMLAddCore(xmlNodePtr xmlcell) const;
 
    int XMLRead(xmlNode *cur);
 
	void DivideWalls(ItList new_node_locations, const Vector from, const Vector to, bool wall_fixed = false, NodeSet *node_set = 0);
 
 signals:
 
  void ChemMonValue(double t, double *x);
 

	
 
 protected:
 
  void XMLAddCore(xmlNodePtr xmlcell) const;
 
  int XMLRead(xmlNode *cur);
 
  void DivideWalls(ItList new_node_locations, const Vector from, const Vector to, bool wall_fixed = false, NodeSet *node_set = 0);
 

	
 
private:
 
 private:
 

	
 
    static QPen *cell_outline_pen;
 
	static double offset[3];
 
    static double factor;
 
	Mesh *m;
 
	void ConstructConnections(void);
 
	void SetWallLengths(void);
 

	
 
  static QPen *cell_outline_pen;
 
  static double offset[3];
 
  static double factor;
 
  Mesh *m;
 
  void ConstructConnections(void);
 
  void SetWallLengths(void);
 
};
 

	
 

	
 
// Boundarypolygon is a special cell; will not increase ncells
 
//  and will not be part of Mesh::cells
 
class BoundaryPolygon : public Cell {
 
	
 
public:
 
	BoundaryPolygon(void) : Cell() {
 
		NCells()--;
 
		index=-1;
 
	}
 
    
 
    BoundaryPolygon(double x,double y,double z=0) : Cell (x,y,z) {
 
		NCells()--;
 
		index=-1;
 
    }
 
	
 
	BoundaryPolygon &operator=(Cell &src) {
 
		Cell::operator=(src);
 
		index=-1;
 
		return *this;
 
	}
 
	virtual void Draw(QGraphicsScene *c, QString tooltip = QString::Null());
 
	
 
	virtual void XMLAdd(xmlNodePtr parent_node) const;
 
	
 
	virtual bool BoundaryPolP(void) const { return true; } 
 

	
 
 public:
 
 BoundaryPolygon(void) : Cell() {
 
    NCells()--;
 
    index=-1;
 
  }
 

	
 
 BoundaryPolygon(double x,double y,double z=0) : Cell (x,y,z) {
 
    NCells()--;
 
    index=-1;
 
  }
 

	
 
  BoundaryPolygon &operator=(Cell &src) {
 
    Cell::operator=(src);
 
    index=-1;
 
    return *this;
 
  }
 
  virtual void Draw(QGraphicsScene *c, QString tooltip = QString::Null());
 

	
 
  virtual void XMLAdd(xmlNodePtr parent_node) const;
 

	
 
  virtual bool BoundaryPolP(void) const { return true; } 
 
};
 

	
 

	
 
#endif
 

	
 
#endif
 
/* finis */
src/cellbase.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <cmath>
 
#include <string>
 
#include <sstream>
 
#include <vector>
 
#include <algorithm>
 
#include <functional>
 
#ifdef QTGRAPHICS
 
#include <QGraphicsScene>
 
#include <qpainter.h>
 
#include <qcolor.h>
 
#include <qfont.h>
 
#include <qwidget.h>
 
//Added by qt3to4:
 
#include <Q3PointArray>
 
#include <fstream>
 
#include "nodeitem.h"
 
#include "cellitem.h"
 
#include "qcanvasarrow.h"
 
#endif
 
#include "nodeset.h"
 

	
 
#include "cellbase.h"
 
#include "wall.h"
 
#include "random.h"
 
#include "parameter.h" 
 
#include "mesh.h"
 
#include "sqr.h"
 
#include "tiny.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
extern Parameter par;
 

	
 
const char* CellBase::boundary_type_names[4] = {"None", "NoFlux", "SourceSink", "SAM"};
 

	
 
#ifndef VLEAFPLUGIN
 
CellsStaticDatamembers *CellBase::static_data_members = new CellsStaticDatamembers();
 
#else
 
CellsStaticDatamembers *CellBase::static_data_members = 0;
 
#endif
 

	
 
CellBase::CellBase(QObject *parent) : 
 
QObject(parent),
 
Vector()
 
  QObject(parent),
 
  Vector()
 
{
 

	
 
	chem=new double[NChem()];
 
	for (int i=0;i<NChem();i++) {
 
		chem[i]=0.;
 
	}
 
	new_chem=new double[NChem()];
 
	for (int i=0;i<NChem();i++) {
 
		new_chem[i]=0.;
 
	}
 
	boundary=None;
 
	index=(NCells()++);
 
	area=0.;
 
	target_area=1;
 
	target_length=0; //par.target_length;
 
	lambda_celllength = 0; //par.lambda_celllength;
 
	intgrl_xx=0.; intgrl_xy=0.; intgrl_yy=0.;
 
	intgrl_x=0.; intgrl_y=0.;
 
	source = false;
 
	source_conc = 0.;
 
	source_chem = 0;
 
	at_boundary=false;
 
	fixed = false;
 
	pin_fixed = false;
 
	stiffness = 0;
 
	marked = false;
 
	dead = false;
 
	div_counter=0;
 
	cell_type = 0;
 
	flag_for_divide = false;
 
	division_axis = 0;
 
  chem=new double[NChem()];
 
  for (int i=0;i<NChem();i++) {
 
    chem[i]=0.;
 
  }
 
  new_chem=new double[NChem()];
 
  for (int i=0;i<NChem();i++) {
 
    new_chem[i]=0.;
 
  }
 
  boundary=None;
 
  index=(NCells()++);
 
  area=0.;
 
  target_area=1;
 
  target_length=0; //par.target_length;
 
  lambda_celllength = 0; //par.lambda_celllength;
 
  intgrl_xx=0.; intgrl_xy=0.; intgrl_yy=0.;
 
  intgrl_x=0.; intgrl_y=0.;
 
  source = false;
 
  source_conc = 0.;
 
  source_chem = 0;
 
  at_boundary=false;
 
  fixed = false;
 
  pin_fixed = false;
 
  stiffness = 0;
 
  marked = false;
 
  dead = false;
 
  div_counter=0;
 
  cell_type = 0;
 
  flag_for_divide = false;
 
  division_axis = 0;
 
}
 

	
 

	
 
CellBase::CellBase(double x,double y,double z) : QObject(), Vector(x,y,z)
 
{
 
#ifndef VLEAFPLUGIN
 
	if (static_data_members == 0) {
 
		static_data_members = new CellsStaticDatamembers();
 
	}
 
  if (static_data_members == 0) {
 
    static_data_members = new CellsStaticDatamembers();
 
  }
 
#endif
 
	chem=new double[NChem()];
 
	for (int i=0;i<NChem();i++) {
 
		chem[i]=0.;
 
	}
 
	new_chem=new double[NChem()];
 
	for (int i=0;i<NChem();i++) {
 
		new_chem[i]=0.;
 
	}
 
	boundary=None;
 
	area=0.;
 
	target_area=1;
 
	target_length=0; //par.target_length;
 
	lambda_celllength=0; // par.lambda_celllength;
 
	
 
	index=(NCells()++);
 
	
 
	intgrl_xx=0.; intgrl_xy=0.; intgrl_yy=0.;
 
	intgrl_x=0.; intgrl_y=0.;
 
	
 
	source = false;
 
	fixed = false;
 
	at_boundary=false;
 
	pin_fixed = false;
 
	stiffness = 0;
 
	marked=false;
 
	dead  = false;
 
	div_counter = 0;
 
	cell_type = 0;
 
	flag_for_divide = false;
 
	division_axis = 0;
 
  chem=new double[NChem()];
 
  for (int i=0;i<NChem();i++) {
 
    chem[i]=0.;
 
  }
 
  new_chem=new double[NChem()];
 
  for (int i=0;i<NChem();i++) {
 
    new_chem[i]=0.;
 
  }
 
  boundary=None;
 
  area=0.;
 
  target_area=1;
 
  target_length=0; //par.target_length;
 
  lambda_celllength=0; // par.lambda_celllength;
 

	
 
  index=(NCells()++);
 

	
 
  intgrl_xx=0.; intgrl_xy=0.; intgrl_yy=0.;
 
  intgrl_x=0.; intgrl_y=0.;
 

	
 
  source = false;
 
  fixed = false;
 
  at_boundary=false;
 
  pin_fixed = false;
 
  stiffness = 0;
 
  marked=false;
 
  dead  = false;
 
  div_counter = 0;
 
  cell_type = 0;
 
  flag_for_divide = false;
 
  division_axis = 0;
 
}
 

	
 
CellBase::CellBase(const CellBase &src) :  Vector(src), QObject()
 
{
 
	
 
	chem=new double[NChem()];
 
	for (int i=0;i<NChem();i++) {
 
		chem[i]=src.chem[i];
 
	}
 
	new_chem=new double[NChem()];
 
	for (int i=0;i<NChem();i++) {
 
		new_chem[i]=src.new_chem[i];
 
	}
 
	boundary=src.boundary;
 
	area=src.area;
 
	target_length=src.target_length;
 
	lambda_celllength=src.lambda_celllength;
 
	
 
	intgrl_xx=src.intgrl_xx; intgrl_xy=src.intgrl_xy; intgrl_yy=src.intgrl_yy;
 
	intgrl_x=src.intgrl_x; intgrl_y=src.intgrl_y;
 
	
 
	target_area=src.target_area;
 
	index=src.index;
 
	nodes=src.nodes;
 
	neighbors=src.neighbors;
 
	walls=src.walls;
 
	source = src.source;
 
	fixed = src.fixed;
 
	source_conc = src.source_conc;
 
	source_chem = src.source_chem;
 
	cellvec = src.cellvec;
 
	at_boundary=src.at_boundary;
 
	pin_fixed = src.pin_fixed;
 
	stiffness = src.stiffness;
 
	marked = src.marked;
 
	dead = src.dead;
 
	cell_type = src.cell_type;
 
	div_counter = src.div_counter;
 
	flag_for_divide = src.flag_for_divide;
 
	division_axis = src.division_axis;
 

	
 
  chem=new double[NChem()];
 
  for (int i=0;i<NChem();i++) {
 
    chem[i]=src.chem[i];
 
  }
 
  new_chem=new double[NChem()];
 
  for (int i=0;i<NChem();i++) {
 
    new_chem[i]=src.new_chem[i];
 
  }
 
  boundary=src.boundary;
 
  area=src.area;
 
  target_length=src.target_length;
 
  lambda_celllength=src.lambda_celllength;
 

	
 
  intgrl_xx=src.intgrl_xx; intgrl_xy=src.intgrl_xy; intgrl_yy=src.intgrl_yy;
 
  intgrl_x=src.intgrl_x; intgrl_y=src.intgrl_y;
 

	
 
  target_area=src.target_area;
 
  index=src.index;
 
  nodes=src.nodes;
 
  neighbors=src.neighbors;
 
  walls=src.walls;
 
  source = src.source;
 
  fixed = src.fixed;
 
  source_conc = src.source_conc;
 
  source_chem = src.source_chem;
 
  cellvec = src.cellvec;
 
  at_boundary=src.at_boundary;
 
  pin_fixed = src.pin_fixed;
 
  stiffness = src.stiffness;
 
  marked = src.marked;
 
  dead = src.dead;
 
  cell_type = src.cell_type;
 
  div_counter = src.div_counter;
 
  flag_for_divide = src.flag_for_divide;
 
  division_axis = src.division_axis;
 
}
 

	
 

	
 
CellBase CellBase::operator=(const CellBase &src) {
 
	Vector::operator=(src);
 
CellBase CellBase::operator=(const CellBase &src)
 
{
 
  Vector::operator=(src);
 

	
 
	for (int i=0;i<NChem();i++) {
 
		chem[i]=src.chem[i];
 
	}
 
	for (int i=0;i<NChem();i++) {
 
		new_chem[i]=src.chem[i];
 
	}
 
	boundary=src.boundary;
 
	area=src.area;
 
	intgrl_xx=src.intgrl_xx; intgrl_xy=src.intgrl_xy; intgrl_yy=src.intgrl_yy;
 
	intgrl_x=src.intgrl_x; intgrl_y=src.intgrl_y;
 
	target_area=src.target_area;
 
	target_length=src.target_length;
 
	lambda_celllength=src.lambda_celllength;
 
	
 
	index=src.index;
 
  for (int i=0;i<NChem();i++) {
 
    chem[i]=src.chem[i];
 
  }
 
  for (int i=0;i<NChem();i++) {
 
    new_chem[i]=src.chem[i];
 
  }
 
  boundary=src.boundary;
 
  area=src.area;
 
  intgrl_xx=src.intgrl_xx; intgrl_xy=src.intgrl_xy; intgrl_yy=src.intgrl_yy;
 
  intgrl_x=src.intgrl_x; intgrl_y=src.intgrl_y;
 
  target_area=src.target_area;
 
  target_length=src.target_length;
 
  lambda_celllength=src.lambda_celllength;
 

	
 
	nodes=src.nodes;
 
	neighbors=src.neighbors;
 
	walls=src.walls;
 
	source = src.source;
 
	fixed = src.fixed;
 
	source_conc = src.source_conc;
 
	source_chem = src.source_chem;
 
	cellvec = src.cellvec;
 
	at_boundary=src.at_boundary;
 
	pin_fixed = src.pin_fixed;
 
	stiffness = src.stiffness;
 
	marked = src.marked;
 
	dead = src.dead;
 
	cell_type = src.cell_type;
 
	div_counter = src.div_counter;
 
	flag_for_divide = src.flag_for_divide;
 
	division_axis = src.division_axis;
 
	return *this;
 
  index=src.index;
 

	
 
  nodes=src.nodes;
 
  neighbors=src.neighbors;
 
  walls=src.walls;
 
  source = src.source;
 
  fixed = src.fixed;
 
  source_conc = src.source_conc;
 
  source_chem = src.source_chem;
 
  cellvec = src.cellvec;
 
  at_boundary=src.at_boundary;
 
  pin_fixed = src.pin_fixed;
 
  stiffness = src.stiffness;
 
  marked = src.marked;
 
  dead = src.dead;
 
  cell_type = src.cell_type;
 
  div_counter = src.div_counter;
 
  flag_for_divide = src.flag_for_divide;
 
  division_axis = src.division_axis;
 
  return *this;
 
}
 

	
 
void CellBase::SetChemical(int c, double conc) {
 
	if (c>=NChem()) {
 
		stringstream error;
 
		error << "SetChemical: value c = " << c << " is out of range\n";
 
		throw error.str().c_str();
 
	}
 
	chem[c]=conc;
 
void CellBase::SetChemical(int c, double conc)
 
{
 
  if (c>=NChem()) {
 
    stringstream error;
 
    error << "SetChemical: value c = " << c << " is out of range\n";
 
    throw error.str().c_str();
 
  }
 
  chem[c]=conc;
 
}
 

	
 
void CellBase::SetTransporters(int ch, double conc) {
 
	if (ch>=NChem()) {
 
		stringstream error;
 
		error << "SetChemical: value ch = " << ch << " is out of range\n";
 
		throw error.str().c_str();
 
	}
 
	for (list<Wall *>::iterator w=walls.begin();
 
		 w!=walls.end();
 
		 w++) {
 
		(*w)->setTransporter(this, ch, conc);
 
	}
 
void CellBase::SetTransporters(int ch, double conc)
 
{
 
  if (ch>=NChem()) {
 
    stringstream error;
 
    error << "SetChemical: value ch = " << ch << " is out of range\n";
 
    throw error.str().c_str();
 
  }
 
  for (list<Wall *>::iterator w=walls.begin();
 
       w!=walls.end();
 
       w++) {
 
    (*w)->setTransporter(this, ch, conc);
 
  }
 
}
 

	
 
ostream &CellBase::print(ostream &os) const {
 
	
 
	
 
	os << "[ index = " << index << " {" << x << ", " << y << ", " << z << "}: {";
 
	
 
	for (int i=0;i<NChem()-1;i++) {
 
		os << chem[i] << ", ";
 
	}
 
	
 
	os << chem[NChem()-1] << " } ]";
 
	
 
	os << endl << "Nodelist = { " << endl;
 
	
 
	for (list<Node *>::const_iterator i =  nodes.begin(); i!=nodes.end(); i++) {
 
		os << (*i)->Index() << "( " << *i << ") ";
 
	}
 
	os << " } ";
 
	
 
	for (list<Wall *>::const_iterator i =  walls.begin(); i!=walls.end(); i++) {
 
		(*i)->print(os);
 
		os << ", ";
 
	} 
 
	os << endl;
 
	
 
	os << " [ area = " << area << " ]";
 
	os << " [ walls = ";
 
	
 
	for (list<Wall *>::const_iterator i= walls.begin();
 
		 i!=walls.end();
 
		 i++) {
 
		os << (*i)->n1->Index() << " -> " << (*i)->n2->Index() << ", " <<  (*i)->c1->Index() << " | " << (*i)->c2->Index() << ", ";
 
	}
 
	os << " ] ";
 
	os << "div_counter = " << div_counter << endl;
 
	os << "cell_type = " << cell_type << endl;
 
	os << endl;
 
	return os;
 
	
 
ostream &CellBase::print(ostream &os) const
 
{
 

	
 

	
 
  os << "[ index = " << index << " {" << x << ", " << y << ", " << z << "}: {";
 

	
 
  for (int i=0;i<NChem()-1;i++) {
 
    os << chem[i] << ", ";
 
  }
 

	
 
  os << chem[NChem()-1] << " } ]";
 

	
 
  os << endl << "Nodelist = { " << endl;
 

	
 
  for (list<Node *>::const_iterator i =  nodes.begin(); i!=nodes.end(); i++) {
 
    os << (*i)->Index() << "( " << *i << ") ";
 
  }
 
  os << " } ";
 

	
 
  for (list<Wall *>::const_iterator i =  walls.begin(); i!=walls.end(); i++) {
 
    (*i)->print(os);
 
    os << ", ";
 
  } 
 
  os << endl;
 

	
 
  os << " [ area = " << area << " ]";
 
  os << " [ walls = ";
 

	
 
  for (list<Wall *>::const_iterator i= walls.begin();
 
       i!=walls.end();
 
       i++) {
 
    os << (*i)->n1->Index() << " -> " << (*i)->n2->Index() << ", " <<  (*i)->c1->Index() << " | " << (*i)->c2->Index() << ", ";
 
  }
 
  os << " ] ";
 
  os << "div_counter = " << div_counter << endl;
 
  os << "cell_type = " << cell_type << endl;
 
  os << endl;
 
  return os;
 
}
 

	
 
ostream &operator<<(ostream &os, const CellBase &c) {
 
	c.print(os);
 
	return os;
 
ostream &operator<<(ostream &os, const CellBase &c)
 
{
 
  c.print(os);
 
  return os;
 
}
 

	
 

	
 
double CellBase::CalcArea(void) const {
 
	
 
	double loc_area=0.;
 
	
 
	for (list<Node *>::const_iterator i=nodes.begin();
 
		 i!=(nodes.end());
 
		 i++) {
 
		
 
		list<Node *>::const_iterator i_plus_1=i; i_plus_1++;
 
		if (i_plus_1==nodes.end())
 
			i_plus_1=nodes.begin();
 
		
 
		loc_area+= (*i)->x * (*i_plus_1)->y;
 
		loc_area-= (*i_plus_1)->x * (*i)->y;
 
	}
 
double CellBase::CalcArea(void) const
 
{
 

	
 
  double loc_area=0.;
 

	
 
  for (list<Node *>::const_iterator i=nodes.begin();
 
       i!=(nodes.end());
 
       i++) {
 

	
 
	// http://technology.niagarac.on.ca/courses/ctec1335/docs/arrays2.pdf	
 
	//return loc_area/2.0; 
 
	return fabs(loc_area)/2.0; 
 
    list<Node *>::const_iterator i_plus_1=i; i_plus_1++;
 
    if (i_plus_1==nodes.end())
 
      i_plus_1=nodes.begin();
 

	
 
    loc_area+= (*i)->x * (*i_plus_1)->y;
 
    loc_area-= (*i_plus_1)->x * (*i)->y;
 
  }
 

	
 
  // http://technology.niagarac.on.ca/courses/ctec1335/docs/arrays2.pdf	
 
  return fabs(loc_area)/2.0; 
 
} 
 

	
 
Vector CellBase::Centroid(void) const {
 
	
 
	double area=0.;
 
	double integral_x_dxdy=0.,integral_y_dxdy=0.;
 
	
 
	for (list<Node *>::const_iterator i=nodes.begin();
 
		 i!=(nodes.end());
 
		 i++) {
 
		
 
		list<Node *>::const_iterator i_plus_1=i; i_plus_1++;
 
		if (i_plus_1==nodes.end())
 
			i_plus_1=nodes.begin();
 
		
 
		area+= (*i)->x * (*i_plus_1)->y;
 
		area-= (*i_plus_1)->x * (*i)->y;
 
		
 
		integral_x_dxdy+=
 
			((*i_plus_1)->x+(*i)->x)*
 
			((*i)->x*(*i_plus_1)->y-
 
			 (*i_plus_1)->x*(*i)->y);
 
		integral_y_dxdy+=
 
			((*i_plus_1)->y+(*i)->y)*
 
			((*i)->x*(*i_plus_1)->y-
 
			 (*i_plus_1)->x*(*i)->y);
 
	}
 
    
 
	//area/=2.0;
 
	area = fabs(area)/2.0;
 
	
 
	integral_x_dxdy/=6.;
 
	integral_y_dxdy/=6.;
 
	
 
	Vector centroid(integral_x_dxdy,integral_y_dxdy,0);
 
	centroid/=area;
 
	return centroid;
 
Vector CellBase::Centroid(void) const
 
{
 

	
 
  double area=0.;
 
  double integral_x_dxdy=0.,integral_y_dxdy=0.;
 

	
 
  for (list<Node *>::const_iterator i=nodes.begin();
 
       i!=(nodes.end());
 
       i++) {
 

	
 
    list<Node *>::const_iterator i_plus_1=i; i_plus_1++;
 
    if (i_plus_1==nodes.end())
 
      i_plus_1=nodes.begin();
 

	
 
    area+= (*i)->x * (*i_plus_1)->y;
 
    area-= (*i_plus_1)->x * (*i)->y;
 

	
 
    integral_x_dxdy+=
 
      ((*i_plus_1)->x+(*i)->x)*
 
      ((*i)->x*(*i_plus_1)->y-
 
       (*i_plus_1)->x*(*i)->y);
 
    integral_y_dxdy+=
 
      ((*i_plus_1)->y+(*i)->y)*
 
      ((*i)->x*(*i_plus_1)->y-
 
       (*i_plus_1)->x*(*i)->y);
 
  }
 

	
 
  area = fabs(area)/2.0;
 

	
 
  integral_x_dxdy/=6.;
 
  integral_y_dxdy/=6.;
 

	
 
  Vector centroid(integral_x_dxdy,integral_y_dxdy,0);
 
  centroid/=area;
 
  return centroid;
 
}
 

	
 

	
 

	
 
void CellBase::SetIntegrals(void) const {
 
	
 
	// Set the initial values for the integrals over x^2,
 
	// xy, yy, x, and y
 
	
 
	// these values will be updated after each move of the CellBase wall
 
	
 
	intgrl_xx=0.; intgrl_xy=0.; intgrl_yy=0.;
 
	intgrl_x=0.; intgrl_y=0.;
 
	area=0.;
 
	list<Node *>::const_iterator nb;
 
	list<Node *>::const_iterator i=nodes.begin();
 
	
 
	for (;
 
		 i!=(nodes.end());
 
		 i++) {
 
		
 
		nb = i; nb++; if (nb==nodes.end()) nb=nodes.begin();
 
		
 
		area+=(*i)->x*(*nb)->y;
 
		area-=(*nb)->x*(*i)->y;
 
		intgrl_xx+= 
 
			((*i)->x*(*i)->x+
 
			 (*nb)->x*(*i)->x+
 
			 (*nb)->x*(*nb)->x ) *
 
			((*i)->x*(*nb)->y-
 
			 (*nb)->x*(*i)->y);
 
		intgrl_xy+= 
 
			((*nb)->x*(*i)->y-
 
			 (*i)->x*(*nb)->y)*
 
			((*i)->x*(2*(*i)->y+(*nb)->y)+
 
			 (*nb)->x*((*i)->y+2*(*nb)->y));
 
		intgrl_yy+=
 
			((*i)->x*(*nb)->y-
 
			 (*nb)->x*(*i)->y)*
 
			((*i)->y*(*i)->y+
 
			 (*nb)->y*(*i)->y+
 
			 (*nb)->y*(*nb)->y );
 
		intgrl_x+=
 
			((*nb)->x+(*i)->x)*
 
			((*i)->x*(*nb)->y-
 
			 (*nb)->x*(*i)->y);
 
		intgrl_y+=
 
			((*nb)->y+(*i)->y)*
 
			((*i)->x*(*nb)->y-
 
			 (*nb)->x*(*i)->y);
 
	}
 
	
 
void CellBase::SetIntegrals(void) const
 
{
 

	
 
  // Set the initial values for the integrals over x^2,
 
  // xy, yy, x, and y
 

	
 
  // these values will be updated after each move of the CellBase wall
 

	
 
  intgrl_xx=0.; intgrl_xy=0.; intgrl_yy=0.;
 
  intgrl_x=0.; intgrl_y=0.;
 
  area=0.;
 
  list<Node *>::const_iterator nb;
 
  list<Node *>::const_iterator i=nodes.begin();
 

	
 
  for (;
 
       i!=(nodes.end());
 
       i++) {
 

	
 
    nb = i; nb++; if (nb==nodes.end()) nb=nodes.begin();
 

	
 
	area = fabs(area)/2.0;
 
	
 
    area+=(*i)->x*(*nb)->y;
 
    area-=(*nb)->x*(*i)->y;
 
    intgrl_xx+= 
 
      ((*i)->x*(*i)->x+
 
       (*nb)->x*(*i)->x+
 
       (*nb)->x*(*nb)->x ) *
 
      ((*i)->x*(*nb)->y-
 
       (*nb)->x*(*i)->y);
 
    intgrl_xy+= 
 
      ((*nb)->x*(*i)->y-
 
       (*i)->x*(*nb)->y)*
 
      ((*i)->x*(2*(*i)->y+(*nb)->y)+
 
       (*nb)->x*((*i)->y+2*(*nb)->y));
 
    intgrl_yy+=
 
      ((*i)->x*(*nb)->y-
 
       (*nb)->x*(*i)->y)*
 
      ((*i)->y*(*i)->y+
 
       (*nb)->y*(*i)->y+
 
       (*nb)->y*(*nb)->y );
 
    intgrl_x+=
 
      ((*nb)->x+(*i)->x)*
 
      ((*i)->x*(*nb)->y-
 
       (*nb)->x*(*i)->y);
 
    intgrl_y+=
 
      ((*nb)->y+(*i)->y)*
 
      ((*i)->x*(*nb)->y-
 
       (*nb)->x*(*i)->y);
 
  }
 
  area = fabs(area)/2.0;
 
}
 

	
 
double CellBase::Length(Vector *long_axis, double *width)  const {
 
	
 
	// Calculate length and axes of CellBase
 
    
 
	// Calculate inertia tensor
 
	// see file inertiatensor.nb for explanation of this method
 
	if (!lambda_celllength) {
 
		
 
		// Without length constraint we do not keep track of the cells'
 
		// moments of inertia. So we must calculate them here.
 
		SetIntegrals();
 
	}
 
	
 
	double intrx=intgrl_x/6.;
 
	double intry=intgrl_y/6.;
 
	double ixx=(intgrl_xx/12.)-(intrx*intrx)/area;
 
	double ixy=(intgrl_xy/24.)+(intrx*intry)/area;
 
	double iyy=(intgrl_yy/12.)-(intry*intry)/area;
 
	
 
	double rhs1=(ixx+iyy)/2., rhs2=sqrt( (ixx-iyy)*(ixx-iyy)+4*ixy*ixy )/2.;
 
    
 
	double lambda_b=rhs1+rhs2;
 
	
 
	// see: http://scienceworld.wolfram.com/physics/MomentofInertiaEllipse.html
 
	//    cerr << "n = " << n << "\n";
 
	
 
	if (long_axis) {
 
		*long_axis = Vector(-ixy, lambda_b - ixx, 0);
 
		//   cerr << "ixx = " << ixx << ", ixy = " << ixy << ", iyy = " << iyy << ", area = " << area << endl;
 
	}
 
	
 
	if (width) {
 
		*width = 4*sqrt((rhs1-rhs2)/area);
 
	}
 
	
 
	return 4*sqrt(lambda_b/area);
 
    
 
	
 
	
 
double CellBase::Length(Vector *long_axis, double *width)  const
 
{
 

	
 
  // Calculate length and axes of CellBase
 

	
 
  // Calculate inertia tensor
 
  // see file inertiatensor.nb for explanation of this method
 
  if (!lambda_celllength) {
 

	
 
    // Without length constraint we do not keep track of the cells'
 
    // moments of inertia. So we must calculate them here.
 
    SetIntegrals();
 
  }
 

	
 
  double intrx=intgrl_x/6.;
 
  double intry=intgrl_y/6.;
 
  double ixx=(intgrl_xx/12.)-(intrx*intrx)/area;
 
  double ixy=(intgrl_xy/24.)+(intrx*intry)/area;
 
  double iyy=(intgrl_yy/12.)-(intry*intry)/area;
 

	
 
  double rhs1=(ixx+iyy)/2., rhs2=sqrt( (ixx-iyy)*(ixx-iyy)+4*ixy*ixy )/2.;
 

	
 
  double lambda_b=rhs1+rhs2;
 

	
 
  // see: http://scienceworld.wolfram.com/physics/MomentofInertiaEllipse.html
 
  //    cerr << "n = " << n << "\n";
 

	
 
  if (long_axis) {
 
    *long_axis = Vector(-ixy, lambda_b - ixx, 0);
 
    //   cerr << "ixx = " << ixx << ", ixy = " << ixy << ", iyy = " << iyy << ", area = " << area << endl;
 
  }
 

	
 
  if (width) {
 
    *width = 4*sqrt((rhs1-rhs2)/area);
 
  }
 

	
 
  return 4*sqrt(lambda_b/area);
 
}
 

	
 
double CellBase::CalcLength(Vector *long_axis, double *width)  const {
 
	
 
	// Calculate length and axes of CellBase, without touching cells raw moments
 
    
 
	// Calculate inertia tensor
 
	// see file inertiatensor.nb for explanation of this method
 
	
 
	double my_intgrl_xx=0., my_intgrl_xy=0., my_intgrl_yy=0.;
 
	double my_intgrl_x=0., my_intgrl_y=0., my_area=0.;
 
	my_area=0.;
 
	list<Node *>::const_iterator nb;
 
	list<Node *>::const_iterator i=nodes.begin();
 
	
 
	for (;
 
		 i!=(nodes.end());
 
		 i++) {
 
		
 
		nb = i; nb++; if (nb==nodes.end()) nb=nodes.begin();
 
		
 
		my_area+=(*i)->x*(*nb)->y;
 
		my_area-=(*nb)->x*(*i)->y;
 
		my_intgrl_xx+= 
 
			((*i)->x*(*i)->x+
 
			 (*nb)->x*(*i)->x+
 
			 (*nb)->x*(*nb)->x ) *
 
			((*i)->x*(*nb)->y-
 
			 (*nb)->x*(*i)->y);
 
		my_intgrl_xy+= 
 
			((*nb)->x*(*i)->y-
 
			 (*i)->x*(*nb)->y)*
 
			((*i)->x*(2*(*i)->y+(*nb)->y)+
 
			 (*nb)->x*((*i)->y+2*(*nb)->y));
 
		my_intgrl_yy+=
 
			((*i)->x*(*nb)->y-
 
			 (*nb)->x*(*i)->y)*
 
			((*i)->y*(*i)->y+
 
			 (*nb)->y*(*i)->y+
 
			 (*nb)->y*(*nb)->y );
 
		my_intgrl_x+=
 
			((*nb)->x+(*i)->x)*
 
			((*i)->x*(*nb)->y-
 
			 (*nb)->x*(*i)->y);
 
		my_intgrl_y+=
 
			((*nb)->y+(*i)->y)*
 
			((*i)->x*(*nb)->y-
 
			 (*nb)->x*(*i)->y);
 
	}
 
	
 
	
 
	//my_area/=2.0;
 
	my_area = fabs(my_area)/2.0;
 
	
 
	
 
	double intrx=my_intgrl_x/6.;
 
	double intry=my_intgrl_y/6.;
 
	double ixx=(my_intgrl_xx/12.)-(intrx*intrx)/my_area;
 
	double ixy=(my_intgrl_xy/24.)+(intrx*intry)/my_area;
 
	double iyy=(my_intgrl_yy/12.)-(intry*intry)/my_area;
 
	
 
	double rhs1=(ixx+iyy)/2., rhs2=sqrt( (ixx-iyy)*(ixx-iyy)+4*ixy*ixy )/2.;
 
    
 
	double lambda_b=rhs1+rhs2;
 
	
 
	// see: http://scienceworld.wolfram.com/physics/MomentofInertiaEllipse.html
 
	//    cerr << "n = " << n << "\n";
 
	
 
	if (long_axis) {
 
		*long_axis = Vector(-ixy, lambda_b - ixx, 0);
 
		//   cerr << "ixx = " << ixx << ", ixy = " << ixy << ", iyy = " << iyy << ", my_area = " << my_area << endl;
 
	}
 
	
 
	if (width) {
 
		*width = 4*sqrt((rhs1-rhs2)/my_area);
 
	}
 
	
 
	return 4*sqrt(lambda_b/my_area);
 
    
 
	
 
	
 
double CellBase::CalcLength(Vector *long_axis, double *width)  const
 
{
 

	
 
  // Calculate length and axes of CellBase, without touching cells raw moments
 

	
 
  // Calculate inertia tensor
 
  // see file inertiatensor.nb for explanation of this method
 

	
 
  double my_intgrl_xx=0., my_intgrl_xy=0., my_intgrl_yy=0.;
 
  double my_intgrl_x=0., my_intgrl_y=0., my_area=0.;
 
  my_area=0.;
 
  list<Node *>::const_iterator nb;
 
  list<Node *>::const_iterator i=nodes.begin();
 

	
 
  for (;
 
       i!=(nodes.end());
 
       i++) {
 

	
 
    nb = i; nb++; if (nb==nodes.end()) nb=nodes.begin();
 

	
 
    my_area+=(*i)->x*(*nb)->y;
 
    my_area-=(*nb)->x*(*i)->y;
 
    my_intgrl_xx+= 
 
      ((*i)->x*(*i)->x+
 
       (*nb)->x*(*i)->x+
 
       (*nb)->x*(*nb)->x ) *
 
      ((*i)->x*(*nb)->y-
 
       (*nb)->x*(*i)->y);
 
    my_intgrl_xy+= 
 
      ((*nb)->x*(*i)->y-
 
       (*i)->x*(*nb)->y)*
 
      ((*i)->x*(2*(*i)->y+(*nb)->y)+
 
       (*nb)->x*((*i)->y+2*(*nb)->y));
 
    my_intgrl_yy+=
 
      ((*i)->x*(*nb)->y-
 
       (*nb)->x*(*i)->y)*
 
      ((*i)->y*(*i)->y+
 
       (*nb)->y*(*i)->y+
 
       (*nb)->y*(*nb)->y );
 
    my_intgrl_x+=
 
      ((*nb)->x+(*i)->x)*
 
      ((*i)->x*(*nb)->y-
 
       (*nb)->x*(*i)->y);
 
    my_intgrl_y+=
 
      ((*nb)->y+(*i)->y)*
 
      ((*i)->x*(*nb)->y-
 
       (*nb)->x*(*i)->y);
 
  }
 

	
 

	
 
  //my_area/=2.0;
 
  my_area = fabs(my_area)/2.0;
 

	
 

	
 
  double intrx=my_intgrl_x/6.;
 
  double intry=my_intgrl_y/6.;
 
  double ixx=(my_intgrl_xx/12.)-(intrx*intrx)/my_area;
 
  double ixy=(my_intgrl_xy/24.)+(intrx*intry)/my_area;
 
  double iyy=(my_intgrl_yy/12.)-(intry*intry)/my_area;
 

	
 
  double rhs1=(ixx+iyy)/2., rhs2=sqrt( (ixx-iyy)*(ixx-iyy)+4*ixy*ixy )/2.;
 

	
 
  double lambda_b=rhs1+rhs2;
 

	
 
  // see: http://scienceworld.wolfram.com/physics/MomentofInertiaEllipse.html
 
  //    cerr << "n = " << n << "\n";
 

	
 
  if (long_axis) {
 
    *long_axis = Vector(-ixy, lambda_b - ixx, 0);
 
    //   cerr << "ixx = " << ixx << ", ixy = " << ixy << ", iyy = " << iyy << ", my_area = " << my_area << endl;
 
  }
 

	
 
  if (width) {
 
    *width = 4*sqrt((rhs1-rhs2)/my_area);
 
  }
 

	
 
  return 4*sqrt(lambda_b/my_area);
 
}
 

	
 

	
 
void CellBase::ConstructNeighborList(void)
 
{
 

	
 
void CellBase::ConstructNeighborList(void) {
 
	
 
	neighbors.clear();
 
	for (//list<Wall *>::const_reverse_iterator wit=walls.rbegin();
 
		 list<Wall *>::const_iterator wit=walls.begin();
 
		 // somehow the reverse_iterator returns by walls needs to be casted to const to let this work.
 
		 // it seems to me it is a bug in the STL implementation...
 
  neighbors.clear();
 
  for (//list<Wall *>::const_reverse_iterator wit=walls.rbegin();
 
       list<Wall *>::const_iterator wit=walls.begin();
 
       // somehow the reverse_iterator returns by walls needs to be casted to const to let this work.
 
       // it seems to me it is a bug in the STL implementation...
 

	
 
       wit!=walls.end();
 
       wit++) {
 

	
 
    if ((*wit)->C1() != this) {
 
      neighbors.push_back((*wit)->C1());
 
    } else {
 
      neighbors.push_back((*wit)->C2());
 
    }
 

	
 
  }
 

	
 
		 wit!=walls.end();
 
		 wit++) {
 
		
 
		if ((*wit)->C1() != this) {
 
			neighbors.push_back((*wit)->C1());
 
		} else {
 
			neighbors.push_back((*wit)->C2());
 
		}
 
		
 
	}
 
	
 
	
 
	// remove all boundary_polygons from the list
 
	list <CellBase *>::iterator e=neighbors.begin();
 
	at_boundary=false;
 
	
 
	do { 
 
		// Code crashes here after cutting off part of the leaf. I can't find the problem.
 
		// Leaving the "Illegal" walls in the simulation helps. (c1=-1 && c2=-1)
 
		// Work-around: define leaf primordium. Save to XML. Restart. Read XML file.
 
		// Sorry about this; I hope to solve this annoying issue later. RM :-).
 
		// All cells in neighbors seem to be okay (I might be messing some part of the memory elsewhere
 
		// during the cutting operation?).
 
		e = find_if(neighbors.begin(),neighbors.end(),mem_fun(&CellBase::BoundaryPolP));
 
		if (e!=neighbors.end()) {
 
			e=neighbors.erase(e);
 
			at_boundary=true;
 
		} else {
 
			break;
 
		}
 

	
 
  // remove all boundary_polygons from the list
 
  list <CellBase *>::iterator e=neighbors.begin();
 
  at_boundary=false;
 

	
 
  do { 
 
    // Code crashes here after cutting off part of the leaf. I can't find the problem.
 
    // Leaving the "Illegal" walls in the simulation helps. (c1=-1 && c2=-1)
 
    // Work-around: define leaf primordium. Save to XML. Restart. Read XML file.
 
    // Sorry about this; I hope to solve this annoying issue later. RM :-).
 
    // All cells in neighbors seem to be okay (I might be messing some part of the memory elsewhere
 
    // during the cutting operation?).
 
    e = find_if(neighbors.begin(),neighbors.end(),mem_fun(&CellBase::BoundaryPolP));
 
    if (e!=neighbors.end()) {
 
      e=neighbors.erase(e);
 
      at_boundary=true;
 
    } else {
 
      break;
 
    }
 
  } while(1);
 
	
 
}
 
	
 
	// Save the cell to a stream so we can reconstruct its state later
 
	void CellBase::Dump(ostream &os) const {
 
		
 
		
 
		os << index << " " << nodes.size() << endl;
 
		
 
		Vector::Dump(os);
 
		os << endl;
 
		
 
		for (list<Node *>::const_iterator i=nodes.begin();i!=nodes.end();i++) {
 
			os << *i << " ";
 
		}
 
		os << endl;
 
		
 
		
 
		os << index << " " << neighbors.size() << endl;
 
		for (list<CellBase *>::const_iterator i=neighbors.begin();i!=neighbors.end();i++) {
 
			os << *i << " ";
 
		}
 
		os << endl;
 
		
 
		os << walls.size() << endl;
 
		/*for (list<Wall *>::const_iterator i=walls.begin();i!=walls.end(); i++) {
 
			(*i)->Dump(os);
 
		}*/
 
		
 
		os << endl;
 
		
 
		os << NChem() << " ";
 
		for (int i=0;i<NChem();i++) {
 
			os << chem[i] << " ";
 
		}
 
		os << endl;
 
		
 
		os << NChem() << " ";
 
		for (int i=0;i<NChem();i++) {
 
			os << new_chem[i] << " ";
 
		}
 
		os << endl;
 
		
 
		os << boundary << " " << area << " " << target_area << " " << target_length << " " << fixed << " " << intgrl_xx << " " << intgrl_xy << " " << intgrl_yy << " " << intgrl_x << " " << intgrl_y << " " << source << " ";
 
		
 
		cellvec.Dump(os);
 
		
 
		os << " " << source_conc << " " << source_chem;
 
		os << endl;
 
		
 
	}
 
	
 
	
 
	
 
	void CellBase::UnfixNodes(void) {
 
		
 
		for (list<Node *>::const_iterator i=nodes.begin();
 
			 i!=nodes.end();
 
			 i++) {
 
			(*i)->Unfix();
 
		}
 
		
 
	}
 
	
 
	void CellBase::FixNodes(void) {
 
		
 
		for (list<Node *>::const_iterator i=nodes.begin();
 
			 i!=nodes.end();
 
			 i++) {
 
			(*i)->Fix();
 
		}
 
		
 
	}
 
	
 
	// returns true if cell is at border
 
	bool CellBase::AtBoundaryP(void) const {
 
		
 
		return at_boundary;
 
	}
 
	
 

	
 
// Save the cell to a stream so we can reconstruct its state later
 
void CellBase::Dump(ostream &os) const
 
{
 

	
 

	
 
  os << index << " " << nodes.size() << endl;
 

	
 
  Vector::Dump(os);
 
  os << endl;
 

	
 
  for (list<Node *>::const_iterator i=nodes.begin();i!=nodes.end();i++) {
 
    os << *i << " ";
 
  }
 
  os << endl;
 

	
 

	
 
  os << index << " " << neighbors.size() << endl;
 
  for (list<CellBase *>::const_iterator i=neighbors.begin();i!=neighbors.end();i++) {
 
    os << *i << " ";
 
  }
 

	
 
  os << endl << walls.size() << endl << endl;
 
  os << NChem() << " ";
 

	
 
  for (int i=0;i<NChem();i++) {
 
    os << chem[i] << " ";
 
  }
 
  os << endl;
 

	
 
  os << NChem() << " ";
 
  for (int i=0;i<NChem();i++) {
 
    os << new_chem[i] << " ";
 
  }
 
  os << endl;
 

	
 
  os << boundary << " " << area << " " << target_area << " " << target_length 
 
     << " " << fixed << " " << intgrl_xx << " " << intgrl_xy << " " << intgrl_yy 
 
     << " " << intgrl_x << " " << intgrl_y << " " << source << " ";
 

	
 
  cellvec.Dump(os);
 

	
 
  os << " " << source_conc << " " << source_chem;
 
  os << endl;
 

	
 
}
 

	
 

	
 
QString CellBase::printednodelist(void) {
 
	QString info_string = "Nodelist = { ";
 
	for (list<Node *>::const_iterator i =  nodes.begin(); i!=nodes.end(); i++) {
 
		info_string += QString("%1 ").arg((*i)->Index());
 
	}
 
	info_string += " } ";
 
	return info_string;
 
void CellBase::UnfixNodes(void)
 
{
 

	
 
  for (list<Node *>::const_iterator i=nodes.begin();
 
       i!=nodes.end();
 
       i++) {
 
    (*i)->Unfix();
 
  }
 

	
 
}
 

	
 

	
 
void CellBase::FixNodes(void)
 
{
 

	
 
  for (list<Node *>::const_iterator i=nodes.begin();
 
       i!=nodes.end();
 
       i++) {
 
    (*i)->Fix();
 
  }
 

	
 
}
 

	
 
// returns true if cell is at border
 
bool CellBase::AtBoundaryP(void) const
 
{
 
  return at_boundary;
 
}
 

	
 

	
 
QString CellBase::printednodelist(void)
 
{
 
  QString info_string = "Nodelist = { ";
 
  for (list<Node *>::const_iterator i =  nodes.begin(); i!=nodes.end(); i++) {
 
    info_string += QString("%1 ").arg((*i)->Index());
 
  }
 
  info_string += " } ";
 
  return info_string;
 
}
 

	
 
/* finis*/
src/cellbase.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
// CellBase derives from Vector, where Vector is simply used as a Vertex
 

	
 
#ifndef _CELLBASE_H_
 
#define _CELLBASE_H_
 

	
 
#include <list>
 
#include <vector>
 
#include <iostream>
 
#include <QString>
 
#include <QDebug>
 

	
 
#include "vector.h"
 
#include "parameter.h"
 
#include "wall.h"
 
#include "warning.h"
 
#include "assert.h"
 

	
 
extern Parameter par;
 
using namespace std;
 

	
 
class Mesh;
 
class Node;
 
class CellBase;
 
class NodeSet;
 

	
 
struct ParentInfo {
 
	
 
	Vector polarization;
 
	double PINmembrane;
 
	double PINendosome;
 
	
 

	
 
  Vector polarization;
 
  double PINmembrane;
 
  double PINendosome;
 
};
 

	
 
// We need a little trick here, to make sure the plugin and the main application will see the same static datamembers
 
// otherwise each have their own instantation.
 
// My solution is as follow. I collect all original statics in a class. The main application instantiates it and
 
// has a static pointer to it. After loading the plugin I set a static pointer to the same class 
 
class CellsStaticDatamembers {
 
	
 
public:
 
	CellsStaticDatamembers(void) {
 
		ncells = 0;
 
		nchem = 0;
 
		base_area = 0.;
 
                #ifdef QDEBUG
 
		qDebug() << "Constructor of CellsStaticDatamembers" << endl;
 
		#endif
 
	}
 
	~CellsStaticDatamembers() {
 
                #ifdef QDEBUG
 
	        qDebug() << "Oops! Desctructor of CellsStaticDatamembers called" << endl;
 
                #endif
 
	}
 
	int ncells;
 
	int nchem;
 
	double base_area;
 

	
 

	
 
 public:
 
  CellsStaticDatamembers(void) {
 
    ncells = 0;
 
    nchem = 0;
 
    base_area = 0.;
 
#ifdef QDEBUG
 
    qDebug() << "Constructor of CellsStaticDatamembers" << endl;
 
#endif
 
  }
 
  ~CellsStaticDatamembers() {
 
#ifdef QDEBUG
 
    qDebug() << "Oops! Desctructor of CellsStaticDatamembers called" << endl;
 
#endif
 
  }
 
  int ncells;
 
  int nchem;
 
  double base_area;
 
};
 

	
 
class CellBase :  public QObject, public Vector 
 
{
 

	
 
	Q_OBJECT
 
  Q_OBJECT
 

	
 
  friend class Mesh;
 
  friend class CellInfo;
 
  friend class Node;
 
  friend class WallBase;
 
  friend class SimPluginInterface;
 

	
 
 public:
 
  CellBase(QObject *parent=0);
 
  CellBase(double x,double y,double z=0); // constructor
 

	
 
  virtual ~CellBase() {
 
    delete[] chem;
 
    delete[] new_chem;
 
    if (division_axis) delete division_axis;
 
    //cerr << "CellBase " << index << " is dying. " << endl;
 
  }
 

	
 
  CellBase(const CellBase &src); // copy constructor
 
  virtual bool BoundaryPolP(void) const { return false; } 
 

	
 

	
 
	friend class Mesh;
 
	friend class CellInfo;
 
	friend class Node;
 
	friend class WallBase;
 
	friend class SimPluginInterface;
 
	
 
 public:
 
	CellBase(QObject *parent=0);
 
	CellBase(double x,double y,double z=0); // constructor
 
	
 
  virtual ~CellBase() {
 
	  delete[] chem;
 
	  delete[] new_chem;
 
	  if (division_axis) delete division_axis;
 
	  //cerr << "CellBase " << index << " is dying. " << endl;
 
  CellBase operator=(const CellBase &src); // assignment operator
 
  CellBase operator=(const Vector &src);
 

	
 
  void SetChemical(int chem, double conc);
 
  inline void SetNewChem(int chem, double conc)
 
  { 
 
    new_chem[chem] = conc;
 
  }
 

	
 
  void SetSource(int chem, double conc)
 
  {
 
    source=true;
 
    source_chem = chem;
 
    source_conc = conc;
 
  }
 

	
 
  // set chem 1 to conc in all membranes of this cell
 
  void SetTransporters(int chem, double conc);
 
  void UnfixNodes(void);
 
  void FixNodes(void);
 
  void UnsetSource(void) {
 
    source = false;
 
  }
 
	
 
	CellBase(const CellBase &src); // copy constructor
 
	virtual bool BoundaryPolP(void) const { return false; } 
 
	
 
	
 
    CellBase operator=(const CellBase &src); // assignment operator
 
    CellBase operator=(const Vector &src);
 
  
 
    void SetChemical(int chem, double conc);
 
    inline void SetNewChem(int chem, double conc) { 
 
      new_chem[chem] = conc;
 
    }
 
    void SetSource(int chem, double conc) {
 
      source=true;
 
      source_chem = chem;
 
      source_conc = conc;
 
	}
 
	// set chem 1 to conc in all membranes of this cell
 
    void SetTransporters(int chem, double conc);
 
    void UnfixNodes(void);
 
    void FixNodes(void);
 
    void UnsetSource(void) {
 
      source = false;
 
    }
 
    
 
	inline bool Source(void) { return source; }
 
    enum boundary_type {None, Noflux, SourceSink, SAM};
 
    static const char * boundary_type_names[4];
 

	
 
  inline bool Source(void) { return source; }
 
  enum boundary_type {None, Noflux, SourceSink, SAM};
 
  static const char * boundary_type_names[4];
 

	
 
  inline const char *BoundaryStr(void) { return boundary_type_names[boundary]; }
 

	
 
    inline const char *BoundaryStr(void) { return boundary_type_names[boundary]; }
 
    
 
    ostream &print(ostream &os) const;
 
  ostream &print(ostream &os) const;
 

	
 
  inline double Chemical(int c) const { // returns the value of chemical c
 
#ifdef _undefined_
 
    qDebug() << endl << "Entering cellbase::chemical(" << c << "), and nchem is: " << NChem() << "." << endl;
 
#endif
 

	
 
    inline double Chemical(int c) const { // returns the value of chemical c
 
    #ifdef _undefined_
 
      qDebug() << endl << "Entering cellbase::chemical(" << c << "), and nchem is: " << NChem() << "." << endl;
 
    #endif
 

	
 
      int nchem = NChem();
 
    int nchem = NChem();
 

	
 
      #ifdef _undefined_
 
      if ((c<0) || (c>=nchem))
 
	MyWarning::warning("CellBase::Chemical says: index c is: %d, but nchem is: %d. Merely return zero", c, nchem);
 
      #endif
 

	
 
      return ((c<0) || (c>=nchem)) ? 0 : chem[c];
 
    }
 

	
 
    
 
    //void print_nblist(void) const;
 
#ifdef _undefined_
 
    if ((c<0) || (c>=nchem))
 
      MyWarning::warning("CellBase::Chemical says: index c is: %d, but nchem is: %d. Merely return zero", c, nchem);
 
#endif
 

	
 
    boundary_type SetBoundary(boundary_type bound) {
 
      if (bound!=None) {
 
      }
 
      return boundary=bound;
 
    }
 
  
 
    boundary_type ResetBoundary(void) {
 
      return boundary=None;
 
    }
 
    boundary_type Boundary(void) const {
 
      return boundary;
 
    }
 
    static int &NChem(void) {
 
      return static_data_members->nchem;
 
    }
 
  
 
    double CalcArea(void) const;
 
    double RecalcArea(void) {
 
      return area = CalcArea();
 
    return ((c<0) || (c>=nchem)) ? 0 : chem[c];
 
  }
 

	
 

	
 
  //void print_nblist(void) const;
 

	
 
  boundary_type SetBoundary(boundary_type bound)
 
  {
 
    if (bound!=None) {
 
    }
 
    
 
    Vector Centroid(void) const;
 
  
 
    void SetIntegrals(void) const;
 
    
 
    double Length(Vector *long_axis = 0, double *width = 0) const;
 
    double CalcLength(Vector *long_axis = 0, double *width = 0) const;
 
    
 
    return boundary=bound;
 
  }
 

	
 
  boundary_type ResetBoundary(void) { return boundary=None; }
 

	
 
    inline int Index(void) const {
 
      return index;
 
    }
 
  
 
  boundary_type Boundary(void) const { return boundary; }
 

	
 
  static int &NChem(void) { return static_data_members->nchem; }
 

	
 
  double CalcArea(void) const;
 

	
 
  double RecalcArea(void) { return area = CalcArea(); }
 

	
 
    void SetTargetArea(double tar_ar) {
 
      target_area=tar_ar;
 
    }
 
    inline void SetTargetLength(double tar_l) {
 
      target_length=tar_l;
 
    }
 
    inline void SetLambdaLength(double lambda_length) {
 
      lambda_celllength = lambda_length;
 
    }
 
    inline double TargetArea(void) {
 
      return target_area;
 
    }
 
  
 
    inline void SetStiffness(double stiff) {
 
      stiffness = stiff;
 
    }
 
  Vector Centroid(void) const;
 

	
 
  void SetIntegrals(void) const;
 

	
 
  double Length(Vector *long_axis = 0, double *width = 0) const;
 
  double CalcLength(Vector *long_axis = 0, double *width = 0) const;
 

	
 

	
 
  inline int Index(void) const { return index; }
 

	
 

	
 
  void SetTargetArea(double tar_ar) { target_area=tar_ar; }
 

	
 
    inline double Stiffness(void) {
 
      return stiffness;
 
    }
 
    inline double EnlargeTargetArea(double da) {
 
      return target_area+=da;
 
    }
 
  
 
    inline double Area(void) const {
 
      return area;
 
    }
 
    
 
	inline void Divide(void) {
 
		flag_for_divide = true;
 
	}
 
	
 
	inline void DivideOverAxis(const Vector &v) {
 
		division_axis = new Vector(v);
 
		flag_for_divide = true;
 
	}
 
	
 
  inline void SetTargetLength(double tar_l) { target_length=tar_l; }
 

	
 
  inline void SetLambdaLength(double lambda_length) { lambda_celllength = lambda_length; }
 

	
 
  inline double TargetArea(void) { return target_area; }
 

	
 
    inline double Circumference(void) const {
 
      double sum=0.;
 
      for (list<Wall *>::const_iterator w=walls.begin();
 
	   w!=walls.end();
 
	   w++) {
 
	sum +=  (*w)->Length();
 
      }
 
      
 
      return sum;
 
    }
 
  inline void SetStiffness(double stiff) { stiffness = stiff; }
 

	
 
  inline double Stiffness(void) { return stiffness; }
 

	
 
  inline double EnlargeTargetArea(double da) { return target_area+=da; }
 

	
 
  inline double Area(void) const { return area; }
 

	
 
	QList<WallBase *> getWalls(void) {
 
		QList<WallBase *> wall_list;
 
		for (list<Wall *>::iterator i=walls.begin();
 
			 i!=walls.end();
 
			 i++) {
 
			wall_list << *i;
 
		}
 
		return wall_list;
 
	}
 
    
 
    void Dump(ostream &os) const;
 
   	
 
	QString printednodelist(void);
 
 
 
  inline void Divide(void) { flag_for_divide = true; }
 

	
 
    
 
    inline bool DeadP(void) { return dead; }
 
    inline void MarkDead(void) { dead  = true; }
 
    
 
	static double &BaseArea(void) { 
 
		return static_data_members->base_area;
 
	}
 
  
 
    void CheckForDivision(void);
 
  inline void DivideOverAxis(const Vector &v)
 
  {
 
    division_axis = new Vector(v);
 
    flag_for_divide = true;
 
  }
 

	
 
	
 
    // write flux from neighboring cells into "flux"
 
    void Flux(double *flux, double *D); 
 
    inline bool FixedP(void) { return fixed; }
 
    inline bool Fix(void) {  FixNodes(); return (fixed=true); }
 
    inline bool Unfix(void) { UnfixNodes(); return (fixed=false);}
 
    inline void setCellVec(Vector cv) { cellvec = cv; }
 
    
 
	bool AtBoundaryP(void) const;
 
    
 
    static inline int &NCells(void) {
 
      return static_data_members->ncells;
 
  inline double Circumference(void) const {
 
    double sum=0.;
 
    for (list<Wall *>::const_iterator w=walls.begin();
 
	 w!=walls.end();
 
	 w++) {
 
      sum +=  (*w)->Length();
 
    }
 

	
 
 
 
   
 
    inline void Mark(void) {
 
      marked=true;
 
    }
 
    inline void Unmark(void) {
 
      marked=false;
 
    }
 
    inline bool Marked(void) const {
 
      return marked;
 
    }
 
    return sum;
 
  }
 

	
 
	//! Returns the sum of chemical "chem" of this CellBase's neighbors
 
    double SumChemicalsOfNeighbors(int chem) {
 
      double sum=0.;
 
      for (list<Wall *>::const_iterator w=walls.begin();
 
	   w!=walls.end();
 
	   w++) {
 
	sum +=  (*w)->Length() * ( (*w)->c1!=this ? (*w)->c1->Chemical(chem) : (*w)->c2->Chemical(chem) );
 
      }
 
      return sum;
 
    }
 

	
 
    //! Generalization of the previous member function
 
    template<class P, class Op> P ReduceNeighbors(Op f) {
 
      P sum=0;
 
      for (list<Wall *>::const_iterator w=walls.begin();
 
	   w!=walls.end();
 
	   w++) {
 
	sum += (*w)->c1 != this ? f( *((*w)->c1) ) : f ( *((*w)->c2) ); 
 
      }
 
      return sum;
 
    }
 

	
 
    //! The same, but now for the walls
 
    template<class P, class Op> P ReduceWalls(Op f, P sum) {
 
      for (list<Wall *>::const_iterator w=walls.begin();
 
	   w!=walls.end();
 
	   w++) {
 
	sum += f( **w ); 
 
      }
 
      return sum;
 
  QList<WallBase *> getWalls(void) {
 
    QList<WallBase *> wall_list;
 
    for (list<Wall *>::iterator i=walls.begin();
 
	 i!=walls.end();
 
	 i++) {
 
      wall_list << *i;
 
    }
 
	
 
	
 
    
 
    
 
    //! The same, but now for the walls AND neighbors
 
    template<class P, class Op> P ReduceCellAndWalls(Op f) {
 
      P sum = 0;
 
      for (list<Wall *>::const_iterator w=walls.begin();
 
	   w!=walls.end();
 
	   w++) {
 
	sum += ((*w)->c1 == this) ? 
 
	  f( ((*w)->c1), ((*w)->c2), *w ) :  
 
	  f( ((*w)->c2), ((*w)->c1), *w );
 
      }
 
      return sum;
 
    return wall_list;
 
  }
 

	
 
  void Dump(ostream &os) const;
 

	
 
  QString printednodelist(void);
 

	
 
  inline bool DeadP(void) { return dead; }
 
  inline void MarkDead(void) { dead  = true; }
 

	
 
  static double &BaseArea(void)
 
  { 
 
    return static_data_members->base_area;
 
  }
 

	
 
  void CheckForDivision(void);
 

	
 
  // write flux from neighboring cells into "flux"
 
  void Flux(double *flux, double *D); 
 
  inline bool FixedP(void) { return fixed; }
 
  inline bool Fix(void) {  FixNodes(); return (fixed=true); }
 
  inline bool Unfix(void) { UnfixNodes(); return (fixed=false);}
 
  inline void setCellVec(Vector cv) { cellvec = cv; }
 

	
 
  bool AtBoundaryP(void) const;
 

	
 
  static inline int &NCells(void)
 
  {
 
    return static_data_members->ncells;
 
  }
 

	
 
  inline void Mark(void)
 
  {
 
    marked=true;
 
  }
 

	
 
  inline void Unmark(void)
 
  {
 
    marked=false;
 
  }
 

	
 
  inline bool Marked(void) const {
 
    return marked;
 
  }
 

	
 
  //! Returns the sum of chemical "chem" of this CellBase's neighbors
 
  double SumChemicalsOfNeighbors(int chem)
 
  {
 
    double sum=0.;
 
    for (list<Wall *>::const_iterator w=walls.begin();
 
	 w!=walls.end();
 
	 w++) {
 
      sum +=  (*w)->Length() * ( (*w)->c1!=this ? (*w)->c1->Chemical(chem) : (*w)->c2->Chemical(chem) );
 
    }
 
    
 
	
 
    //! Sum transporters at this CellBase's side of the walls
 
    double SumTransporters(int ch) {
 
      double sum=0.;
 
      for (list<Wall *>::const_iterator w=walls.begin();
 
	   w!=walls.end();
 
	   w++) {
 
	sum += (*w)->getTransporter(this, ch);
 
      
 
      }
 
      
 
      return sum;
 
    return sum;
 
  }
 

	
 
  //! Generalization of the previous member function
 
  template<class P, class Op> P ReduceNeighbors(Op f) {
 
    P sum=0;
 
    for (list<Wall *>::const_iterator w=walls.begin();
 
	 w!=walls.end();
 
	 w++) {
 
      sum += (*w)->c1 != this ? f( *((*w)->c1) ) : f ( *((*w)->c2) ); 
 
    }
 
    return sum;
 
  }
 

	
 
  //! The same, but now for the walls
 
  template<class P, class Op> P ReduceWalls(Op f, P sum) {
 
    for (list<Wall *>::const_iterator w=walls.begin();
 
	 w!=walls.end();
 
	 w++) {
 
      sum += f( **w ); 
 
    }
 
    return sum;
 
  }
 

	
 
    inline int NumberOfDivisions(void) { return div_counter; }
 
    
 
    //! Sum transporters at this CellBase's side of the walls
 
    double SumLengthTransporters(int ch) {
 
      double sum=0.;
 
      for (list<Wall *>::const_iterator w=walls.begin();
 
	   w!=walls.end();
 
	   w++) {
 
	sum += (*w)->getTransporter(this, ch) * (*w)->Length();
 
      
 
      }
 
      
 
      return sum;
 
  //! The same, but now for the walls AND neighbors
 
  template<class P, class Op> P ReduceCellAndWalls(Op f)
 
  {
 
    P sum = 0;
 
    for (list<Wall *>::const_iterator w=walls.begin();
 
	 w!=walls.end();
 
	 w++) {
 
      sum += ((*w)->c1 == this) ? 
 
	f( ((*w)->c1), ((*w)->c2), *w ) :  
 
	f( ((*w)->c2), ((*w)->c1), *w );
 
    }
 
    return sum;
 
  }
 

	
 

	
 
  //! Sum transporters at this CellBase's side of the walls
 
  double SumTransporters(int ch)
 
  {
 
    double sum=0.;
 
    for (list<Wall *>::const_iterator w=walls.begin();
 
	 w!=walls.end();
 
	 w++) {
 
      sum += (*w)->getTransporter(this, ch);
 

	
 
    }
 
    
 
	
 
    
 
    double SumLengthTransportersChemical(int trch, int ch) {
 
      double sum=0.;
 
      for (list<Wall *>::const_iterator w=walls.begin();
 
	   w!=walls.end();
 
	   w++) {
 
	sum += (*w)->getTransporter(this, trch) * ( (*w)->c1!=this ? (*w)->c1->Chemical(ch) : (*w)->c2->Chemical(ch) );
 
	
 
      }
 
      
 
      return sum;
 
    return sum;
 
  }
 

	
 
  inline int NumberOfDivisions(void) { return div_counter; }
 

	
 
  //! Sum transporters at this CellBase's side of the walls
 
  double SumLengthTransporters(int ch)
 
  {
 
    double sum=0.;
 
    for (list<Wall *>::const_iterator w=walls.begin();
 
	 w!=walls.end();
 
	 w++) {
 
      sum += (*w)->getTransporter(this, ch) * (*w)->Length();
 

	
 
    }
 
	inline int CellType(void) const { return cell_type; } 
 
	inline void SetCellType(int ct) { cell_type = ct; }
 
    return sum;
 
  }
 

	
 

	
 

	
 
    
 
	static void SetNChem(int new_nchem) {
 
		if (NCells()) {
 
			MyWarning::error("CellBase::SetNChem says: not permitted, call SetNChem after deleting all cells.");
 
		} else {
 
			NChem() = new_nchem;
 
		}
 
	}
 
	
 
	inline double TargetLength() const { return target_length; } 
 
  double SumLengthTransportersChemical(int trch, int ch)
 
  {
 
    double sum=0.;
 
    for (list<Wall *>::const_iterator w=walls.begin();
 
	 w!=walls.end();
 
	 w++) {
 
      sum += (*w)->getTransporter(this, trch) * ( (*w)->c1!=this ? (*w)->c1->Chemical(ch) : (*w)->c2->Chemical(ch) );
 

	
 
    }
 
    return sum;
 
  }
 
  inline int CellType(void) const { return cell_type; } 
 
  inline void SetCellType(int ct) { cell_type = ct; }
 

	
 
	static inline CellsStaticDatamembers *GetStaticDataMemberPointer(void) { return static_data_members; }
 
	
 
protected:
 
	// (define a list of Node* iterators)
 
	typedef list < list<Node *>::iterator > ItList;
 

	
 
    int index;
 

	
 
	inline void SetChemToNewchem(void) {
 
		for (int c=0;c<CellBase::NChem();c++) {
 
			chem[c]=new_chem[c];
 
		}
 
  static void SetNChem(int new_nchem)
 
  {
 
    if (NCells()) {
 
      MyWarning::error("CellBase::SetNChem says: not permitted, call SetNChem after deleting all cells.");
 
    } else {
 
      NChem() = new_nchem;
 
    }
 
    inline void SetNewChemToChem(void) {
 
		for (int c=0;c<CellBase::NChem();c++) {
 
			new_chem[c]=chem[c];
 
		}
 
    }
 
	inline double NewChem(int c) const { return new_chem[c]; }
 
	
 
  }
 

	
 
  inline double TargetLength() const { return target_length; } 
 

	
 
  static inline CellsStaticDatamembers *GetStaticDataMemberPointer(void) { return static_data_members; }
 

	
 
 protected:
 
    list<Node *> nodes;
 
    void ConstructNeighborList(void);
 
	long wall_list_index (Wall *elem) const;
 
  // (define a list of Node* iterators)
 
  typedef list < list<Node *>::iterator > ItList;
 

	
 
    // DATA MEMBERS
 
    
 
    // list of nodes, in clockwise order
 
  
 
    // a (non-ordered) list of neighboring cells (actually I think the
 
    // introduction of ConstructWalls() has made these
 
    // lists ordered (clockwise), but I am not yet 100% sure...).
 
    list<CellBase *> neighbors;
 
  int index;
 

	
 
    list<Wall *> walls;
 
  
 
    double *chem;
 
    double *new_chem;
 
  
 
    boundary_type boundary;
 
    mutable double area;
 
    double target_area;
 
    double target_length;
 
    double lambda_celllength;
 
  inline void SetChemToNewchem(void)
 
  {
 
    for (int c=0;c<CellBase::NChem();c++) {
 
      chem[c]=new_chem[c];
 
    }
 
  }
 
  inline void SetNewChemToChem(void)
 
  {
 
    for (int c=0;c<CellBase::NChem();c++) {
 
      new_chem[c]=chem[c];
 
    }
 
  }
 
  inline double NewChem(int c) const { return new_chem[c]; }
 

	
 
    double stiffness; // stiffness like in Hogeweg (2000)
 
 protected:
 
  list<Node *> nodes;
 
  void ConstructNeighborList(void);
 
  long wall_list_index (Wall *elem) const;
 

	
 
  // DATA MEMBERS
 

	
 
  // list of nodes, in clockwise order
 

	
 
  // a (non-ordered) list of neighboring cells (actually I think the
 
  // introduction of ConstructWalls() has made these
 
  // lists ordered (clockwise), but I am not yet 100% sure...).
 
  list<CellBase *> neighbors;
 

	
 
  list<Wall *> walls;
 

	
 
    bool fixed;
 
    bool pin_fixed;
 
    bool at_boundary; 
 
    bool dead; 
 
	bool flag_for_divide;
 
	
 
	Vector *division_axis;
 
	
 
	int cell_type;
 
	
 
    
 
    // for length constraint
 
    mutable double intgrl_xx, intgrl_xy, intgrl_yy, intgrl_x, intgrl_y;
 
    
 
    bool source;
 
    Vector cellvec;
 
	
 
	// STATIC DATAMEMBERS MOVED TO CLASS
 
	static CellsStaticDatamembers *static_data_members;
 
	double source_conc;
 
    int source_chem;
 
	
 
    // PRIVATE MEMBER FUNCTIONS
 
    inline static void ClearNCells(void) {
 
      NCells()=0;
 
    }
 
    
 
    bool marked;
 
    int div_counter;
 
  double *chem;
 
  double *new_chem;
 

	
 
  boundary_type boundary;
 
  mutable double area;
 
  double target_area;
 
  double target_length;
 
  double lambda_celllength;
 

	
 
  double stiffness; // stiffness like in Hogeweg (2000)
 

	
 
  bool fixed;
 
  bool pin_fixed;
 
  bool at_boundary; 
 
  bool dead; 
 
  bool flag_for_divide;
 

	
 
  Vector *division_axis;
 
  int cell_type;
 

	
 
  // for length constraint
 
  mutable double intgrl_xx, intgrl_xy, intgrl_yy, intgrl_x, intgrl_y;
 

	
 
  bool source;
 
  Vector cellvec;
 

	
 
  // STATIC DATAMEMBERS MOVED TO CLASS
 
  static CellsStaticDatamembers *static_data_members;
 
  double source_conc;
 
  int source_chem;
 

	
 
  // PRIVATE MEMBER FUNCTIONS
 
  inline static void ClearNCells(void)
 
  {
 
    NCells()=0;
 
  }
 

	
 
  bool marked;
 
  int div_counter;
 
};
 

	
 
ostream &operator<<(ostream &os, const CellBase &v);
 

	
 
inline Vector PINdir(CellBase *here, CellBase *nb, Wall *w) {
 
	  nb = NULL; // assignment merely to obviate compilation warning
 
	  return w->getTransporter( here, 1)  *  w->getInfluxVector(here);
 
inline Vector PINdir(CellBase *here, CellBase *nb, Wall *w)
 
{
 
  nb = NULL; // assignment merely to obviate compilation warning
 
  return w->getTransporter( here, 1)  *  w->getInfluxVector(here);
 
}
 

	
 

	
 
#endif
 

	
 

	
 

	
 

	
 

	
 
/* finis*/
src/cellitem.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include<QGraphicsScene>
 
#include "cellitem.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
CellItem::CellItem( Cell *c, QGraphicsScene *canvas )
 
  : QGraphicsPolygonItem( 0, canvas ), SimItemBase( c, canvas){
 
}
 

	
 
void CellItem::userMove(double dx, double dy) {
 
void CellItem::userMove(double dx, double dy)
 
{
 
  QGraphicsPolygonItem::moveBy( dx, dy );
 

	
 
  // also move the cell itself
 
  class_cast<Cell *>(obj)->x += (dx/Cell::Magnification());
 
  class_cast<Cell *>(obj)->y += (dy/Cell::Magnification());
 
  
 

	
 
  class_cast<Cell*>(obj)->Move( (dx/Cell::Magnification()), (dy/Cell::Magnification()) );
 
}
 

	
 

	
 
QPainterPath CellItem::shape() const { return QGraphicsPolygonItem::shape(); }
 
QRectF CellItem::boundingRect() const { return QGraphicsPolygonItem::boundingRect(); }
 

	
 

	
 
/* finis */
src/cellitem.h
Show inline comments
 
/*
 
 *  VirtualLeaf
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#ifndef _CELLITEM_H_
 
#define _CELLITEM_H_
 

	
 
#include <QGraphicsScene>
 
#include <QGraphicsPolygonItem>
 
#include <QPainter>
 
#include "simitembase.h"
 
#include "cell.h"
 

	
 

	
 
class CellItem : public QGraphicsPolygonItem, public SimItemBase
 
{
 
public:
 
 public:
 
  CellItem( Cell *n, QGraphicsScene *canvas );
 
  virtual ~CellItem() {}
 
  Cell &getCell(void) const { return *class_cast<Cell*>(obj); }
 
  virtual void userMove(double dx, double dy);  
 
  QPainterPath shape() const;
 
  QRectF boundingRect() const;
 

	
 
 private:
 

	
 
};
 

	
 
#endif
 

	
 
/* finis */
src/curvecolors.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _CURVECOLORS_H_
 
#define _CURVECOLORS_H_
 

	
 
#include <QStringList>
 

	
 
class CurveColors {
 

	
 
 public:
 
  CurveColors(void) {
 
    colors += QString("red");
 
    colors += QString("darkgreen");
 
    colors += QString("blue");
 
    colors += QString("purple");
 
    colors += QString("powderblue");
 
    colors += QString("darkgreen");
 
    colors += QString("darkcyan");
 
    colors += QString("burlywood");
 
    colors += QString("deeppink");
 
    colors += QString("deepskyblue");
 
    colors += QString("fuchsia");
 
    colors += QString("lawngreen");
 
    colors += QString("lavenderblush");
 
    colors += QString("pink");
 
    colors += QString("purple");
 
    colors += QString("navy");
 
    colors += QString("greenyellow");
 
    colors += QString("mintcream");
 
    colors += QString("saddlebrown");
 
    colors += QString("salmon");
 
    colors += QString("cornsilk");
 
    colors += QString("darkmagenta");
 
    colors += QString("chocolate");
 
    colors += QString("ivory");
 
    colors += QString("khaki");
 
    colors += QString("moccasin");
 
    colors += QString("mediumturquoise");
 
    colors += QString("mediumorchid");
 
    colors += QString("darkgray");
 
    colors += QString("lightseagreen");
 
    colors += QString("royalblue");
 
    colors += QString("darkred");
 
    colors += QString("violet");
 
    colors += QString("lavender");
 
    colors += QString("silver");
 
    colors += QString("slategray");
 
    colors += QString("ghostwhite");
 
    colors += QString("forestgreen");
 
    colors += QString("lightgrey");
 
    colors += QString("brown");
 
    colors += QString("lightgoldenrodyellow");
 
    colors += QString("darkblue");
 
    colors += QString("lime");
 
    colors += QString("darkkhaki");
 
    colors += QString("oldlace");
 
    colors += QString("springgreen");
 
    colors += QString("darkseagreen");
 
    colors += QString("skyblue");
 
    colors += QString("teal");
 
    colors += QString("lightsalmon");
 
    colors += QString("midnightblue");
 
    colors += QString("mediumslateblue");
 
    colors += QString("darkslateblue");
 
    colors += QString("indianred");
 
    colors += QString("honeydew");
 
    colors += QString("lemonchiffon");
 
    colors += QString("peru");
 
    colors += QString("snow");
 
    colors += QString("mistyrose");
 
    colors += QString("darkslategrey");
 
    colors += QString("gainsboro");
 
    colors += QString("mediumpurple");
 
    colors += QString("grey");
 
    colors += QString("palegoldenrod");
 
    colors += QString("linen");
 
    colors += QString("dimgrey");
 
    colors += QString("firebrick");
 
    colors += QString("lightcyan");
 
    colors += QString("steelblue");
 
    colors += QString("orangered");
 
    colors += QString("darkgoldenrod");
 
    colors += QString("turquoise");
 
    colors += QString("blueviolet");
 
    colors += QString("rosybrown");
 
    colors += QString("lightslategrey");
 
    colors += QString("lightgray");
 
    colors += QString("orchid");
 
    colors += QString("darkturquoise");
 
    colors += QString("darkorange");
 
    colors += QString("plum");
 
    colors += QString("dimgray");
 
    colors += QString("crimson");
 
    colors += QString("mediumaquamarine");
 
    colors += QString("chartreuse");
 
    colors += QString("limegreen");
 
    colors += QString("cadetblue");
 
    colors += QString("mediumblue");
 
    colors += QString("papayawhip");
 
    colors += QString("tan");
 
    colors += QString("dodgerblue");
 
    colors += QString("orange");
 
    colors += QString("lightblue");
 
    colors += QString("coral");
 
    colors += QString("blue");
 
    colors += QString("sandybrown");
 
    colors += QString("slategrey");
 
    colors += QString("lightpink");
 
    colors += QString("sienna");
 
    colors += QString("indigo");
 
    colors += QString("seashell");
 
    colors += QString("lightskyblue");
 
    colors += QString("paleturquoise");
 
    colors += QString("darkslategray");
 
    colors += QString("darkolivegreen");
 
    colors += QString("mediumspringgreen");
 
    colors += QString("floralwhite");
 
    colors += QString("lightyellow");
 
    colors += QString("palegreen");
 
    colors += QString("red");
 
    colors += QString("lightgreen");
 
    colors += QString("cyan");
 
    colors += QString("hotpink");
 
    colors += QString("cornflowerblue");
 
    colors += QString("maroon");
 
    colors += QString("magenta");
 
    colors += QString("lightsteelblue");
 
    colors += QString("gray");
 
    colors += QString("green");
 
    colors += QString("darkviolet");
 
    colors += QString("palevioletred");
 
    colors += QString("darksalmon");
 
    colors += QString("seagreen");
 
    colors += QString("tomato");
 
    colors += QString("olive");
 
    colors += QString("slateblue");
 
    colors += QString("peachpuff");
 
    colors += QString("gold");
 
    colors += QString("mediumseagreen");
 
    colors += QString("darkorchid");
 
    colors += QString("lightslategray");
 
    colors += QString("lightcoral");
 
    colors += QString("mediumvioletred");
 
    colors += QString("thistle");
 
  }
 
  QString &operator[](int i) {
 
    if (i>=colors.size() || i<0) {
 
      throw("Color number out of range in curvecolors.h");
 
    } else
 
      return colors[i];
 
  }
 
 private:
 
  QStringList colors;
 
};
 
#endif
 

	
 
/* finis */
src/data_plot.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include <stdlib.h>
 
#include <qwt_painter.h>
 
#include <qwt_plot_canvas.h>
 
#include <qwt_plot_marker.h>
 
#include <qwt_plot_curve.h>
 
#include <qwt_scale_widget.h>
 
#include <qwt_legend.h>
 
#include <qwt_scale_draw.h>
 
#include <qwt_math.h>
 
#include <QDialog>
 
#include <QString>
 
#include <QStringList>
 
#include <QDebug>
 
#include <iostream>
 
#include "data_plot.h"
 

	
 
using namespace std;
 

	
 
static const string _module_id("$Id$");
 

	
 
//
 
//  Initialize main window
 
//
 
DataPlot::DataPlot(QWidget *parent, const QString title, const QStringList curvenames ):
 
  QwtPlot(parent),
 
  d_interval(0),
 
  d_timerId(-1)
 
{
 

	
 
  // Number of curves is number of names given
 
  ncurves = curvenames.size();
 
  
 

	
 
  // allocate data and curves
 
  d_t = new double[PLOT_SIZE];
 
  d_x = new double *[ncurves];
 
  d_x[0] = new double[ncurves*PLOT_SIZE];
 
  for (int i=1;i<ncurves;i++) {
 
    d_x[i]=d_x[i-1]+PLOT_SIZE;
 
  }
 
  
 

	
 
  // Disable polygon clipping
 
  QwtPainter::setDeviceClipping(false);
 

	
 
  alignScales();
 
    
 

	
 
  //  Initialize data
 
  
 
  
 
  for (int i = 0; i< PLOT_SIZE; i++) {
 
    d_t[i] = 0.;     // time axis
 
  }
 

	
 
  for (int i=0;i<ncurves * PLOT_SIZE;i++) {
 
    d_x[0][i]=0.;
 
  }
 

	
 
  // Assign a title
 
  setTitle(title);
 
  insertLegend(new QwtLegend(), QwtPlot::BottomLegend);
 

	
 
  // Insert curves
 
  curves = new QwtPlotCurve[ncurves];
 
  for (int i=0;i<ncurves;i++) {
 

	
 
    curves[i].setTitle(curvenames[i]);
 
    curves[i].attach(this);
 
    curves[i].setPen(QPen(curvecolors[i]));
 
    QString col(curvecolors[i]);
 

	
 
    #ifdef QDEBUG
 
#ifdef QDEBUG
 
    qDebug() << "Curvecolor " << col.toStdString() << endl;
 
    #endif
 
#endif
 

	
 
    curves[i].setRawData(d_t, d_x[i], PLOT_SIZE);
 
  }
 
    
 

	
 
  // Axis 
 
  setAxisTitle(QwtPlot::xBottom, "Time");
 

	
 
  setAxisTitle(QwtPlot::yLeft, "Level");
 
  setAxisScale(QwtPlot::yLeft, 0, 10);
 

	
 
  data_pos = 0;
 

	
 
}
 

	
 
DataPlot::~DataPlot(void) {
 
DataPlot::~DataPlot(void)
 
{
 
  delete[] d_t ;
 
  delete[] d_x[0];
 
  delete[] d_x;
 
  delete[] curves;
 
}
 

	
 
//
 
//  Set a plain canvas frame and align the scales to it
 
//
 
void DataPlot::alignScales()
 
{
 
    // The code below shows how to align the scales to
 
    // the canvas frame, but is also a good example demonstrating
 
    // why the spreaded API needs polishing.
 
  // The code below shows how to align the scales to
 
  // the canvas frame, but is also a good example demonstrating
 
  // why the spreaded API needs polishing.
 

	
 
  canvas()->setFrameStyle(QFrame::Box | QFrame::Plain );
 
  canvas()->setLineWidth(1);
 

	
 
    canvas()->setFrameStyle(QFrame::Box | QFrame::Plain );
 
    canvas()->setLineWidth(1);
 
    
 
    for ( int i = 0; i < QwtPlot::axisCnt; i++ )
 
  for ( int i = 0; i < QwtPlot::axisCnt; i++ )
 
    {
 
        QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(i);
 
        if ( scaleWidget )
 
            scaleWidget->setMargin(0);
 
      QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(i);
 
      if ( scaleWidget )
 
	scaleWidget->setMargin(0);
 

	
 
        QwtScaleDraw *scaleDraw = (QwtScaleDraw *)axisScaleDraw(i);
 
        if ( scaleDraw )
 
            scaleDraw->enableComponent(QwtAbstractScaleDraw::Backbone, false);
 
      QwtScaleDraw *scaleDraw = (QwtScaleDraw *)axisScaleDraw(i);
 
      if ( scaleDraw )
 
	scaleDraw->enableComponent(QwtAbstractScaleDraw::Backbone, false);
 
    }
 
}
 

	
 

	
 
//  Generate new values 
 
void DataPlot::AddValue(double t,double *x)
 
{
 

	
 
  //  std::cerr << "AddValue receives: " << t << ", " << y << ", " << z << std::endl;
 
  
 

	
 
  // Plot slowly fills up, then shifts to the left
 
  if ( data_pos >= PLOT_SIZE ) {
 
    
 

	
 
    for ( int j = 0; j < PLOT_SIZE - 1; j++ )
 
      d_t[j] = d_t[j+1];
 

	
 
    for ( int i=0;i<ncurves;i++) {
 
      for ( int j = 0; j < PLOT_SIZE - 1; j++ )
 
	d_x[i][j] = d_x[i][j+1];
 
    }
 
    data_pos = PLOT_SIZE - 1;
 
    
 
  } 
 

	
 
  d_t[data_pos] = t;
 

	
 
  for ( int i=0;i<ncurves;i++) {
 
    curves[i].setRawData(d_t, d_x[i], data_pos);
 
    d_x[i][data_pos] = x[i];
 
  }
 
					       
 

	
 
  setAxisScale(QwtPlot::xBottom, d_t[0], t);
 
  
 
  data_pos++;
 

	
 
  // update the display
 
  replot();
 
  
 

	
 
}
 

	
 

	
 
PlotDialog::PlotDialog(QWidget *parent, const QString title, const QStringList curvenames):
 
  QDialog(parent) 
 
{
 
  
 
  plot = new DataPlot(this,title,curvenames);
 
  
 
  plot->resize(400,300);
 
  
 
  show();
 

	
 
}
 

	
 
PlotDialog::~PlotDialog(void) {
 
  
 
PlotDialog::~PlotDialog(void)
 
{
 
  delete plot;
 
}
 

	
 
/* finis */
src/data_plot.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#ifndef _DATA_PLOT_H_
 
#define _DATA_PLOT_H_
 

	
 
#include <QDialog>
 
#include <qwt_plot.h>
 
#include <iostream>
 
#include <QFile>
 
#include <QTextStream>
 
#include <qwt_plot_curve.h>
 
#include "curvecolors.h"
 

	
 
const int PLOT_SIZE = 1000; 
 

	
 
class DataPlot : public QwtPlot
 
{
 
    Q_OBJECT
 
  Q_OBJECT
 

	
 
public:
 
 public:
 
  DataPlot(QWidget *parent, const QString title, const QStringList curvenames);
 
  virtual ~DataPlot(void);
 
public slots:
 
    void AddValue(double t, double *x);
 
  public slots:
 
  void AddValue(double t, double *x);
 

	
 
private:
 
    void alignScales();
 
 private:
 
  void alignScales();
 

	
 
    double *d_t; 
 
    double **d_x; 
 
  double *d_t; 
 
  double **d_x; 
 

	
 
    int d_interval; // timer in ms
 
    int d_timerId;
 
    
 
    QwtPlotCurve *curves;
 
    int data_pos;
 
    int ncurves;
 
    
 
    CurveColors curvecolors;
 
  int d_interval; // timer in ms
 
  int d_timerId;
 

	
 
  QwtPlotCurve *curves;
 
  int data_pos;
 
  int ncurves;
 

	
 
  CurveColors curvecolors;
 

	
 
 protected:
 
    // to write contents of DataPlot to a file
 
    QFile *datfile;
 
    QTextStream datstream;
 

	
 
  // to write contents of DataPlot to a file
 
  QFile *datfile;
 
  QTextStream datstream;
 
};
 

	
 
class PlotDialog : public QDialog {
 

	
 
Q_OBJECT
 
 public:
 
  Q_OBJECT
 
    public:
 
  PlotDialog(QWidget *parent, const QString title, const QStringList curvenames);
 
  ~PlotDialog(void);
 
  public slots:
 
  void AddValue(double t, double *x) {
 
    //std::cerr << "AddValue receives: " << t << ", " << y << ", " << z << std::endl;
 
    plot->AddValue(t,x);
 
  }
 
 private:
 
  DataPlot *plot;
 
};
 

	
 
#endif
 

	
 
/* finis */
src/far_mem_5.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _FAR_MEM_5_h_
 
#define _FAR_MEM_5_h_
 

	
 
template <class _Arg1,  class _Result>
 
	struct my_1_function
 
	{
 
typedef _Arg1 argument_type1;
 
typedef _Result result_type;  ///<  result_type is the return type
 
};
 
  struct my_1_function
 
  {
 
    typedef _Arg1 argument_type1;
 
    typedef _Result result_type;  ///<  result_type is the return type
 
  };
 
template <class Result, class Type,  class Param1>
 
class far_1_arg_mem_fun_t : public my_1_function<Param1, Result> {
 
public:
 
explicit far_1_arg_mem_fun_t(Type &ir_typ, Result (Type::*i_pmf)(Param1)) {
 
			m_ptyp = &ir_typ;
 
			m_pmf = i_pmf;
 
		};
 
Result operator()(Param1 i_prm1) { return (m_ptyp->*(m_pmf))(i_prm1); };
 
  class far_1_arg_mem_fun_t : public my_1_function<Param1, Result> {
 
 public:
 
    explicit far_1_arg_mem_fun_t(Type &ir_typ, Result (Type::*i_pmf)(Param1)) {
 
      m_ptyp = &ir_typ;
 
      m_pmf = i_pmf;
 
    };
 
    Result operator()(Param1 i_prm1) { return (m_ptyp->*(m_pmf))(i_prm1); };
 

	
 
protected:
 
Type *m_ptyp;
 
Result (Type::*m_pmf)(Param1);
 
 protected:
 
    Type *m_ptyp;
 
    Result (Type::*m_pmf)(Param1);
 
};
 

	
 
template <class Result, class Type, class Param1>far_1_arg_mem_fun_t<Result,Type,Param1> far_1_arg_mem_fun(Type &ir_typ, Result (Type::*i_pmf)(Param1) ) {
 
	return far_1_arg_mem_fun_t<Result,Type,Param1>(ir_typ,i_pmf);
 
 }
 
template <class Result, class Type, 
 
  class Param1>far_1_arg_mem_fun_t<Result,Type,Param1> far_1_arg_mem_fun(Type &ir_typ, Result (Type::*i_pmf)(Param1) )
 
{
 
  return far_1_arg_mem_fun_t<Result,Type,Param1>(ir_typ,i_pmf);
 
}
 

	
 
template <class _Arg1, class _Arg2,  class _Result>
 
	struct my_2_function
 
	{
 
typedef _Arg1 argument_type1;
 
typedef _Arg2 argument_type2;
 
typedef _Result result_type;  ///<  result_type is the return type
 
};
 
  struct my_2_function
 
  {
 
    typedef _Arg1 argument_type1;
 
    typedef _Arg2 argument_type2;
 
    typedef _Result result_type;  ///<  result_type is the return type
 
  };
 

	
 
template <class Result, class Type,  class Param1, class Param2>
 
class far_2_arg_mem_fun_t : public my_2_function<Param1, Param2, Result> {
 
public:
 
explicit far_2_arg_mem_fun_t(Type &ir_typ, Result (Type::*i_pmf)(Param1, Param2)) {
 
			m_ptyp = &ir_typ;
 
			m_pmf = i_pmf;
 
		};
 
Result operator()(Param1 i_prm1, Param2 i_prm2) { return (m_ptyp->*(m_pmf))(i_prm1, i_prm2); };
 
  class far_2_arg_mem_fun_t : public my_2_function<Param1, Param2, Result> {
 
 public:
 
    explicit far_2_arg_mem_fun_t(Type &ir_typ, Result (Type::*i_pmf)(Param1, Param2)) {
 
      m_ptyp = &ir_typ;
 
      m_pmf = i_pmf;
 
    };
 
    Result operator()(Param1 i_prm1, Param2 i_prm2) { return (m_ptyp->*(m_pmf))(i_prm1, i_prm2); };
 

	
 
protected:
 
Type *m_ptyp;
 
Result (Type::*m_pmf)(Param1, Param2);
 
 protected:
 
    Type *m_ptyp;
 
    Result (Type::*m_pmf)(Param1, Param2);
 
};
 

	
 
template <class Result, class Type, class Param1, class Param2>far_2_arg_mem_fun_t<Result,Type,Param1, Param2> far_2_arg_mem_fun(Type &ir_typ, Result (Type::*i_pmf)(Param1, Param2) ) {
 
	return far_2_arg_mem_fun_t<Result,Type,Param1, Param2>(ir_typ,i_pmf);
 
 }
 
template <class Result, class Type, class Param1, 
 
  class Param2>far_2_arg_mem_fun_t<Result,Type,Param1, Param2> far_2_arg_mem_fun(Type &ir_typ, Result (Type::*i_pmf)(Param1, Param2) ) {
 
  return far_2_arg_mem_fun_t<Result,Type,Param1, Param2>(ir_typ,i_pmf);
 
}
 

	
 
template <class _Arg1, class _Arg2, class _Arg3,  class _Result>
 
	struct my_3_function
 
	{
 
typedef _Arg1 argument_type1;
 
typedef _Arg2 argument_type2;
 
typedef _Arg3 argument_type3;
 
typedef _Result result_type;  ///<  result_type is the return type
 
};
 
  struct my_3_function
 
  {
 
    typedef _Arg1 argument_type1;
 
    typedef _Arg2 argument_type2;
 
    typedef _Arg3 argument_type3;
 
    typedef _Result result_type;  ///<  result_type is the return type
 
  };
 

	
 
template <class Result, class Type,  class Param1, class Param2, class Param3>
 
class far_3_arg_mem_fun_t : public my_3_function<Param1, Param2, Param3, Result> {
 
public:
 
explicit far_3_arg_mem_fun_t(Type &ir_typ, Result (Type::*i_pmf)(Param1, Param2, Param3)) {
 
			m_ptyp = &ir_typ;
 
			m_pmf = i_pmf;
 
		};
 
Result operator()(Param1 i_prm1, Param2 i_prm2, Param3 i_prm3) { return (m_ptyp->*(m_pmf))(i_prm1, i_prm2, i_prm3); };
 
  class far_3_arg_mem_fun_t : public my_3_function<Param1, Param2, Param3, Result> {
 
 public:
 
    explicit far_3_arg_mem_fun_t(Type &ir_typ, Result (Type::*i_pmf)(Param1, Param2, Param3)) {
 
      m_ptyp = &ir_typ;
 
      m_pmf = i_pmf;
 
    };
 
    Result operator()(Param1 i_prm1, Param2 i_prm2, Param3 i_prm3) { return (m_ptyp->*(m_pmf))(i_prm1, i_prm2, i_prm3); };
 

	
 
protected:
 
Type *m_ptyp;
 
Result (Type::*m_pmf)(Param1, Param2, Param3);
 
 protected:
 
    Type *m_ptyp;
 
    Result (Type::*m_pmf)(Param1, Param2, Param3);
 
};
 

	
 
template <class Result, class Type, class Param1, class Param2, class Param3>far_3_arg_mem_fun_t<Result,Type,Param1, Param2, Param3> far_3_arg_mem_fun(Type &ir_typ, Result (Type::*i_pmf)(Param1, Param2, Param3) ) {
 
	return far_3_arg_mem_fun_t<Result,Type,Param1, Param2, Param3>(ir_typ,i_pmf);
 
 }
 
template <class Result, class Type, class Param1, class Param2, 
 
class Param3>far_3_arg_mem_fun_t<Result,Type,Param1, Param2, Param3> far_3_arg_mem_fun(Type &ir_typ, Result (Type::*i_pmf)(Param1, Param2, Param3) ) {
 
  return far_3_arg_mem_fun_t<Result,Type,Param1, Param2, Param3>(ir_typ,i_pmf);
 
}
 

	
 
template <class _Arg1, class _Arg2, class _Arg3, class _Arg4,  class _Result>
 
	struct my_4_function
 
	{
 
typedef _Arg1 argument_type1;
 
typedef _Arg2 argument_type2;
 
typedef _Arg3 argument_type3;
 
typedef _Arg4 argument_type4;
 
typedef _Result result_type;  ///<  result_type is the return type
 
};
 
  struct my_4_function
 
  {
 
    typedef _Arg1 argument_type1;
 
    typedef _Arg2 argument_type2;
 
    typedef _Arg3 argument_type3;
 
    typedef _Arg4 argument_type4;
 
    typedef _Result result_type;  ///<  result_type is the return type
 
  };
 

	
 
template <class Result, class Type,  class Param1, class Param2, class Param3, class Param4>
 
class far_4_arg_mem_fun_t : public my_4_function<Param1, Param2, Param3, Param4, Result> {
 
public:
 
explicit far_4_arg_mem_fun_t(Type &ir_typ, Result (Type::*i_pmf)(Param1, Param2, Param3, Param4)) {
 
			m_ptyp = &ir_typ;
 
			m_pmf = i_pmf;
 
		};
 
Result operator()(Param1 i_prm1, Param2 i_prm2, Param3 i_prm3, Param4 i_prm4) { return (m_ptyp->*(m_pmf))(i_prm1, i_prm2, i_prm3, i_prm4); };
 
  class far_4_arg_mem_fun_t : public my_4_function<Param1, Param2, Param3, Param4, Result> {
 
 public:
 
    explicit far_4_arg_mem_fun_t(Type &ir_typ, Result (Type::*i_pmf)(Param1, Param2, Param3, Param4)) {
 
      m_ptyp = &ir_typ;
 
      m_pmf = i_pmf;
 
    };
 
    Result operator()(Param1 i_prm1, Param2 i_prm2, Param3 i_prm3, Param4 i_prm4) { return (m_ptyp->*(m_pmf))(i_prm1, i_prm2, i_prm3, i_prm4); };
 

	
 
protected:
 
Type *m_ptyp;
 
Result (Type::*m_pmf)(Param1, Param2, Param3, Param4);
 
 protected:
 
    Type *m_ptyp;
 
    Result (Type::*m_pmf)(Param1, Param2, Param3, Param4);
 
};
 

	
 
template <class Result, class Type, class Param1, class Param2, class Param3, class Param4>far_4_arg_mem_fun_t<Result,Type,Param1, Param2, Param3, Param4> far_4_arg_mem_fun(Type &ir_typ, Result (Type::*i_pmf)(Param1, Param2, Param3, Param4) ) {
 
	return far_4_arg_mem_fun_t<Result,Type,Param1, Param2, Param3, Param4>(ir_typ,i_pmf);
 
 }
 
  return far_4_arg_mem_fun_t<Result,Type,Param1, Param2, Param3, Param4>(ir_typ,i_pmf);
 
}
 

	
 
template <class _Arg1, class _Arg2, class _Arg3, class _Arg4, class _Arg5,  class _Result>
 
	struct my_5_function
 
	{
 
typedef _Arg1 argument_type1;
 
typedef _Arg2 argument_type2;
 
typedef _Arg3 argument_type3;
 
typedef _Arg4 argument_type4;
 
typedef _Arg5 argument_type5;
 
typedef _Result result_type;  ///<  result_type is the return type
 
};
 
  struct my_5_function
 
  {
 
    typedef _Arg1 argument_type1;
 
    typedef _Arg2 argument_type2;
 
    typedef _Arg3 argument_type3;
 
    typedef _Arg4 argument_type4;
 
    typedef _Arg5 argument_type5;
 
    typedef _Result result_type;  ///<  result_type is the return type
 
  };
 

	
 
template <class Result, class Type,  class Param1, class Param2, class Param3, class Param4, class Param5>
 
class far_5_arg_mem_fun_t : public my_5_function<Param1, Param2, Param3, Param4, Param5, Result> {
 
public:
 
explicit far_5_arg_mem_fun_t(Type &ir_typ, Result (Type::*i_pmf)(Param1, Param2, Param3, Param4, Param5)) {
 
			m_ptyp = &ir_typ;
 
			m_pmf = i_pmf;
 
		};
 
Result operator()(Param1 i_prm1, Param2 i_prm2, Param3 i_prm3, Param4 i_prm4, Param5 i_prm5) { return (m_ptyp->*(m_pmf))(i_prm1, i_prm2, i_prm3, i_prm4, i_prm5); };
 
  class far_5_arg_mem_fun_t : public my_5_function<Param1, Param2, Param3, Param4, Param5, Result> {
 
 public:
 
    explicit far_5_arg_mem_fun_t(Type &ir_typ, Result (Type::*i_pmf)(Param1, Param2, Param3, Param4, Param5)) {
 
      m_ptyp = &ir_typ;
 
      m_pmf = i_pmf;
 
    };
 
    Result operator()(Param1 i_prm1, Param2 i_prm2, Param3 i_prm3, Param4 i_prm4, Param5 i_prm5) { return (m_ptyp->*(m_pmf))(i_prm1, i_prm2, i_prm3, i_prm4, i_prm5); };
 

	
 
protected:
 
Type *m_ptyp;
 
Result (Type::*m_pmf)(Param1, Param2, Param3, Param4, Param5);
 
 protected:
 
    Type *m_ptyp;
 
    Result (Type::*m_pmf)(Param1, Param2, Param3, Param4, Param5);
 
};
 

	
 
template <class Result, class Type, class Param1, class Param2, class Param3, class Param4, class Param5>far_5_arg_mem_fun_t<Result,Type,Param1, Param2, Param3, Param4, Param5> far_5_arg_mem_fun(Type &ir_typ, Result (Type::*i_pmf)(Param1, Param2, Param3, Param4, Param5) ) {
 
	return far_5_arg_mem_fun_t<Result,Type,Param1, Param2, Param3, Param4, Param5>(ir_typ,i_pmf);
 
 }
 
  return far_5_arg_mem_fun_t<Result,Type,Param1, Param2, Param3, Param4, Param5>(ir_typ,i_pmf);
 
}
 

	
 
#endif
 

	
 
/* finis */
src/flux_function.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _FLUX_FUNCTION_h_
 
#define _FLUX_FUNCTION_h_
 

	
 
// This header file defines a macro "SumFluxFromWalls" that attempts to hide this 
 
// horrendously confusing member function wrapper construct from VirtualLeaf's end users
 

	
 
// required format of flux_function is:
 
// double [model class name]::[function name](CellBase *this_cell, CellBase *adjacent_cell, Wall *w)
 
// e.g.:
 
// double MyModel::PINflux(CellBase *this_cell, CellBase *adjacent_cell, Wall *w)
 

	
 
#include "far_mem_5.h"
 

	
 
#define SumFluxFromWalls( _vleafcellp_, _flux_function_ ) \
 
(( _vleafcellp_->ReduceCellAndWalls<double>( far_3_arg_mem_fun( *this, &_flux_function_ ) ) ))
 
  (( _vleafcellp_->ReduceCellAndWalls<double>( far_3_arg_mem_fun( *this, &_flux_function_ ))))
 

	
 
#endif
 

	
 
/* finis */
src/forwardeuler.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <cmath>
 
#include <iostream> 
 
#include "forwardeuler.h"
 
#include "warning.h"
 
#include "maxmin.h"
 
#include <string>
 

	
 
using namespace std;
 

	
 
static const string _module_id("$Id$");
 

	
 
// The value Errcon equals (5/Safety) raised to the power (1/PGrow), see use below.
 

	
 
const double ForwardEuler::Safety  = 0.9;
 
const double ForwardEuler::PGrow = -0.2;
 
const double ForwardEuler::Pshrnk = -0.25;
 
const double ForwardEuler::Errcon = 1.89e-4;
 
const double ForwardEuler::Maxstp = 10000000;
 
const double ForwardEuler::Tiny = 1.0e-30;
 
  
 

	
 

	
 

	
 
/* User storage for intermediate results. Preset kmax and dxsav in the calling program. If kmax =
 
   0 results are stored at approximate intervals dxsav in the arrays xp[1..kount], yp[1..nvar]
 
   [1..kount], where kount is output by odeint. Defining declarations for these variables, with
 
   memoryallo cations xp[1..kmax] and yp[1..nvar][1..kmax] for the arrays, should be in
 
   the calling program.*/
 

	
 
void ForwardEuler::odeint(double *ystart, int nvar, double x1, double x2, double eps, double h1, double hmin, int *nok, int *nbad)
 
/* Runge-Kutta driver with adaptive stepsize control. Integrate starting values ystart[1..nvar]
 
  from x1 to x2 with accuracy eps, storing intermediate results in global variables. h1 should
 
  be set as a guessed first stepsize, hmin as the minimum allowed stepsize (can be zero). On
 
  output nok and nbad are the number of good and bad (but retried and fixed) steps taken, and
 
  ystart is replaced byv alues at the end of the integration interval. derivs is the user-supplied
 
  routine for calculating the right-hand side derivative, while rkqs is the name of the stepper
 
  routine to be used. */
 
   from x1 to x2 with accuracy eps, storing intermediate results in global variables. h1 should
 
   be set as a guessed first stepsize, hmin as the minimum allowed stepsize (can be zero). On
 
   output nok and nbad are the number of good and bad (but retried and fixed) steps taken, and
 
   ystart is replaced byv alues at the end of the integration interval. derivs is the user-supplied
 
   routine for calculating the right-hand side derivative, while rkqs is the name of the stepper
 
   routine to be used. */
 
{
 
  static bool warning_issued = false;
 

	
 
  eps = hmin = 0.0; // use assignment merely to obviate compilation warning
 
  nbad = nok = NULL;
 

	
 
  if (!warning_issued) {
 
    cerr << "Using inaccurate method ForwardEuler\n";
 
    warning_issued=true;
 
    //MyWarning::warning("Using inaccurate method ForwardEuler");
 
  }
 
  // N.B. Not for serious use and not fully usage compatible with RungeKutta
 
  // simply for testing API of integrator.
 
  
 

	
 
  double *y,*dydx;
 
  y=new double[nvar];
 
  dydx=new double[nvar];
 
  double x=x1;
 
    
 

	
 
  for (int i=0;i<nvar;i++) y[i]=ystart[i];
 

	
 
  //if (kmax > 0) xsav=x-dxsav*2.0; //Assures storage of first step.
 

	
 
  dydx=new double[nvar];
 

	
 
  for (int nstp=0;nstp<Maxstp;nstp++) {
 
    
 

	
 
    derivs(x,y,dydx);
 
    
 

	
 
    if (kmax > 0 && kount < kmax-1) {
 
      xp[kount]=x; //Store intermediate results.
 
      for (int i=0;i<nvar;i++) yp[i][kount]=y[i];
 
      kount++;
 
      //xsav=x;
 
    }
 

	
 

	
 
    for (int i=0;i<nvar;i++) {
 
      y[i]=y[i] + h1 * dydx[i];
 
    }
 
      
 

	
 
    x = x + h1;
 

	
 
    if ((x-x2)*(x2-x1) >= 0.0) { //Are we done?
 
      goto done;
 
    }
 

	
 

	
 
  }
 

	
 
 done:
 
  for (int i=0;i<nvar;i++) ystart[i]=y[i];
 
  if (kmax) {
 
    xp[kount]=x; //Save final step.
 
    for (int i=0;i<nvar;i++) yp[i][kount]=y[i];
 
    
 

	
 
  }
 
  
 

	
 
  delete[] dydx;
 
  delete[] y;
 
  return; //Normal exit.
 
}
 

	
 
}
 
/* finis */
src/forwardeuler.h
Show inline comments
 
/*
 
 *  VirtualLeaf
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _FORWARDEULER_H_
 
#define _FORWARDEULER_H_
 

	
 
class ForwardEuler  {
 

	
 
 public:
 
  ForwardEuler(void) {
 
    kmax=kount=0;
 
    dxsav=0.;
 
    xp=0;
 
    yp=0;
 
  }
 
  
 

	
 
  virtual ~ForwardEuler() {}
 
  
 

	
 
  void odeint(double ystart[], int nvar, double x1, double x2, double eps, double h1,
 
	      double hmin, int *nok, int *nbad);
 
  
 

	
 
  // implement this function in a derived class
 
 protected:
 
  virtual void derivs(double x, double *y, double *dxdy) = 0;
 
  int kmax,kount;
 
  double *xp,**yp,dxsav;
 
  
 

	
 
 private:
 

	
 
  static const double Safety;
 
  static const double PGrow;
 
  static const double Pshrnk;
 
  static const double Errcon;
 
  static const double Maxstp;
 
  static const double Tiny;
 
  
 

	
 
};
 
#endif
 

	
 
/* finis */
src/infobar.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _INFOBAR_H_
 
#define _INFOBAR_H_
 

	
 

	
 
#include <q3mainwindow.h>
 
#include <QLabel>
 
#include <QBoxLayout>
 

	
 
class InfoBar : public Q3DockWindow {
 

	
 
	Q_OBJECT
 
public:
 
  Q_OBJECT
 
    public:
 

	
 
  InfoBar(void) : Q3DockWindow() { 
 

	
 
    virtleaf = new QLabel();
 
    SetText("undefined");
 

	
 
	InfoBar(void) : Q3DockWindow() { 
 
		
 
		virtleaf = new QLabel();
 
		SetText("undefined");
 
		
 
		setHorizontalStretchable(true);
 
		boxLayout()->addStretch();
 
		boxLayout()->addWidget(virtleaf);//, Qt::AlignHCenter);
 
		boxLayout()->addStretch();
 
	}
 
	
 
	void SetText(QString text) {
 
		virtleaf->setText(QString("<h1>The Virtual Leaf</h1>\n<center><b>Model:</b> <i>%1</i></center>").arg(text));
 
	}
 
	
 
private:
 
	QLabel *virtleaf;
 
    setHorizontalStretchable(true);
 
    boxLayout()->addStretch();
 
    boxLayout()->addWidget(virtleaf);//, Qt::AlignHCenter);
 
    boxLayout()->addStretch();
 
  }
 

	
 
  void SetText(QString text) {
 
    virtleaf->setText(QString("<h1>The Virtual Leaf</h1>\n<center><b>Model:</b> <i>%1</i></center>").arg(text));
 
  }
 

	
 
 private:
 
  QLabel *virtleaf;
 
};
 

	
 
#endif
 
\ No newline at end of file
 
#endif
 

	
 
/* finis */
src/mainbase.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <libxml/xpath.h>
 
#include <libxml/xmlreader.h>
 

	
 
#include "mainbase.h"
 
#include "xmlwrite.h"
 

	
 
#include <sstream>
 
#include <string>
 

	
 
static const std::string _module_id("$Id$");
 

	
 
xmlNode *MainBase::XMLSettingsTree(void) const {
 
	
 
	xmlNode *xmlsettings = xmlNewNode(NULL, BAD_CAST "settings");
 
	{
 
		xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
		xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_cell_centers");
 
		ostringstream text;
 
		text << bool_name(showcentersp);
 
		xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
	}
 
	{
 
		xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
		xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_nodes");
 
		ostringstream text;
 
		text << bool_name(showmeshp);
 
		xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
	}
 
	{
 
		xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
		xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_node_numbers");
 
		ostringstream text;
 
		text << bool_name(shownodenumbersp);
 
		xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
	}
 
	{
 
		xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
		xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_cell_numbers");
 
		ostringstream text;
 
		text << bool_name(showcellnumbersp);
 
		xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
	}
 
	{
 
		xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
		xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_border_cells");
 
		ostringstream text;
 
		text << bool_name(showbordercellp);
 
		xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
	}
 
	{
 
		xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
		xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_cell_axes");
 
		ostringstream text;
 
		text << bool_name(showcellsaxesp);
 
		xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
	}
 
	{
 
		xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
		xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_cell_strain");
 
		ostringstream text;
 
		text << bool_name(showcellstrainp);
 
		xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
	}
 
	{
 
		xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
		xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_fluxes");
 
		ostringstream text;
 
		text << bool_name(showfluxesp);
 
		xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
	}
 
	{
 
		xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
		xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_walls");
 
		ostringstream text;
 
		text << bool_name(showwallsp);
 
		xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
	}
 
	{
 
		xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
		xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_apoplasts");
 
		ostringstream text;
 
		text << bool_name(showapoplastsp);
 
		xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
	}
 
	{
 
		xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
		xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "save_movie_frames");
 
		ostringstream text;
 
		text << bool_name(movieframesp);
 
		xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
	}
 
	{
 
		xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
		xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_only_leaf_boundary");
 
		ostringstream text;
 
		text << bool_name(showboundaryonlyp);
 
		xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
	}
 
	{
 
		xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
		xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "cell_growth");
 
		ostringstream text;
 
		text << bool_name(dynamicscellsp);
 
		xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
	}
 
	{
 
		xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
		xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "hide_cells");
 
		ostringstream text;
 
		text << bool_name(hidecellsp);
 
		xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
	}
 
	
 
	return xmlsettings;
 

	
 
  xmlNode *xmlsettings = xmlNewNode(NULL, BAD_CAST "settings");
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_cell_centers");
 
    ostringstream text;
 
    text << bool_name(showcentersp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_nodes");
 
    ostringstream text;
 
    text << bool_name(showmeshp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_node_numbers");
 
    ostringstream text;
 
    text << bool_name(shownodenumbersp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_cell_numbers");
 
    ostringstream text;
 
    text << bool_name(showcellnumbersp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_border_cells");
 
    ostringstream text;
 
    text << bool_name(showbordercellp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_cell_axes");
 
    ostringstream text;
 
    text << bool_name(showcellsaxesp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_cell_strain");
 
    ostringstream text;
 
    text << bool_name(showcellstrainp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_fluxes");
 
    ostringstream text;
 
    text << bool_name(showfluxesp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_walls");
 
    ostringstream text;
 
    text << bool_name(showwallsp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_apoplasts");
 
    ostringstream text;
 
    text << bool_name(showapoplastsp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "save_movie_frames");
 
    ostringstream text;
 
    text << bool_name(movieframesp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_only_leaf_boundary");
 
    ostringstream text;
 
    text << bool_name(showboundaryonlyp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "cell_growth");
 
    ostringstream text;
 
    text << bool_name(dynamicscellsp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "hide_cells");
 
    ostringstream text;
 
    text << bool_name(hidecellsp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  return xmlsettings;
 
}
 

	
 
void MainBase::XMLReadSettings(xmlNode *settings) {
 
	
 
	// Many files have no settings section, so don't complain about it.
 
	// Defaults will be used instead.
 
	if (settings == 0) {
 
		return;
 
	}
 
	
 
	xmlNode *cur = settings->xmlChildrenNode;
 
	
 
	while (cur!=NULL) {
 
		
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"setting"))){
 
			
 
			xmlChar *name = xmlGetProp(cur, BAD_CAST "name");
 
			xmlChar *val = xmlGetProp(cur, BAD_CAST "val");
 
			if (!xmlStrcmp(name, (const xmlChar *)"show_cell_centers")) {
 
				showcentersp = strtobool( (const char *)val );
 
			}
 
			if (!xmlStrcmp(name, (const xmlChar *)"show_nodes")) {
 
				showmeshp = strtobool( (const char *)val );
 
			}
 
			if (!xmlStrcmp(name, (const xmlChar *)"show_node_numbers")) {
 
				shownodenumbersp = strtobool( (const char *)val );
 
			}
 
			if (!xmlStrcmp(name, (const xmlChar *)"show_cell_numbers")) {
 
				showcellnumbersp = strtobool( (const char *)val );
 
			}
 
			if (!xmlStrcmp(name, (const xmlChar *)"show_border_cells")) {
 
				showbordercellp = strtobool( (const char *)val );
 
			}
 
			if (!xmlStrcmp(name, (const xmlChar *)"show_cell_axes")) {
 
				showcellsaxesp = strtobool( (const char *)val );
 
			}
 
			if (!xmlStrcmp(name, (const xmlChar *)"show_cell_strain")) {
 
				showcellstrainp = strtobool( (const char *)val );
 
			}
 
			if (!xmlStrcmp(name, (const xmlChar *)"show_fluxes")) {
 
				showfluxesp = strtobool( (const char *)val );
 
			}
 
			if (!xmlStrcmp(name, (const xmlChar *)"show_walls")) {
 
				showwallsp = strtobool( (const char *)val );
 
			}
 
			if (!xmlStrcmp(name, (const xmlChar *)"show_apoplasts")) {
 
				showapoplastsp = strtobool( (const char *)val );
 
			}
 
			if (!xmlStrcmp(name, (const xmlChar *)"save_movie_frames")) {
 
				movieframesp = strtobool( (const char *)val );
 
			}
 
			if (!xmlStrcmp(name, (const xmlChar *)"show_only_leaf_boundary")) {
 
				showboundaryonlyp = strtobool( (const char *)val );
 
			}
 
			if (!xmlStrcmp(name, (const xmlChar *)"cell_growth")) {
 
				dynamicscellsp = strtobool( (const char *)val );
 
			}
 
			if (!xmlStrcmp(name,(const xmlChar *)"hide_cells")) {
 
				hidecellsp = strtobool( (const char *)val ); 
 
			}
 
			
 
			xmlFree(name);
 
			xmlFree(val);
 
			
 
			
 
		}
 
		cur=cur->next;
 
	}
 
	
 
void MainBase::XMLReadSettings(xmlNode *settings)
 
{
 

	
 
  // Many files have no settings section, so don't complain about it.
 
  // Defaults will be used instead.
 
  if (settings == 0) {
 
    return;
 
  }
 

	
 
  xmlNode *cur = settings->xmlChildrenNode;
 

	
 
  while (cur!=NULL) {
 

	
 
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"setting"))){
 

	
 
      xmlChar *name = xmlGetProp(cur, BAD_CAST "name");
 
      xmlChar *val = xmlGetProp(cur, BAD_CAST "val");
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_cell_centers")) {
 
	showcentersp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_nodes")) {
 
	showmeshp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_node_numbers")) {
 
	shownodenumbersp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_cell_numbers")) {
 
	showcellnumbersp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_border_cells")) {
 
	showbordercellp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_cell_axes")) {
 
	showcellsaxesp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_cell_strain")) {
 
	showcellstrainp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_fluxes")) {
 
	showfluxesp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_walls")) {
 
	showwallsp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_apoplasts")) {
 
	showapoplastsp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"save_movie_frames")) {
 
	movieframesp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_only_leaf_boundary")) {
 
	showboundaryonlyp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"cell_growth")) {
 
	dynamicscellsp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name,(const xmlChar *)"hide_cells")) {
 
	hidecellsp = strtobool( (const char *)val ); 
 
      }
 

	
 
      xmlFree(name);
 
      xmlFree(val);
 
    }
 
    cur=cur->next;
 
  }
 
}
 

	
 
void MainBase::Save(const char *fname, const char *format, int sizex, int sizey) {
 
	
 
	Vector ll,ur;
 
	mesh.BoundingBox(ll, ur);
 
	
 
	if (QString(fname).isEmpty()) {
 
		MyWarning::warning("No output filename given. Saving nothing.\n");
 
		return;
 
	}
 
	
 
	
 
	ll*=Cell::Magnification(); ur*=Cell::Magnification();
 
	
 
	// give the leaf some space
 
	Vector border = ((ur-ll)/5.);
 
	
 
	if (!QString(format).contains("pdf", Qt::CaseInsensitive)) {
 
	
 
		QImage *image = new QImage(QSize(sizex, sizey), QImage::Format_RGB32);
 
		image->fill(QColor(Qt::white).rgb());
 
		QPainter *painter=new QPainter(image);
 
		canvas.render(painter);
 
		if (!image->save(QString(fname))) {
 
			MyWarning::warning("Image not saved successfully. Is the disk full or the extension not recognized?");
 
		};
 
		delete painter;
 
		delete image;
 
	} else {
 
		QPrinter pdf(QPrinter::HighResolution);
 
		pdf.setOutputFileName(fname);
 
		pdf.setOutputFormat(QPrinter::PdfFormat);
 
		QPainter painter(&pdf);
 
		canvas.render(&painter, QRectF(), QRectF(-5000,-5000, 10000, 10000));
 
		
 
		cerr << "Rendering to printer\n";
 
	}
 
void MainBase::Save(const char *fname, const char *format, int sizex, int sizey)
 
{
 

	
 
  Vector ll,ur;
 
  mesh.BoundingBox(ll, ur);
 

	
 
  if (QString(fname).isEmpty()) {
 
    MyWarning::warning("No output filename given. Saving nothing.\n");
 
    return;
 
  }
 

	
 
  ll*=Cell::Magnification(); ur*=Cell::Magnification();
 

	
 
  // give the leaf some space
 
  Vector border = ((ur-ll)/5.);
 

	
 
  if (!QString(format).contains("pdf", Qt::CaseInsensitive)) {
 

	
 
    QImage *image = new QImage(QSize(sizex, sizey), QImage::Format_RGB32);
 
    image->fill(QColor(Qt::white).rgb());
 
    QPainter *painter=new QPainter(image);
 
    canvas.render(painter);
 
    if (!image->save(QString(fname))) {
 
      MyWarning::warning("Image not saved successfully. Is the disk full or the extension not recognized?");
 
    };
 
    delete painter;
 
    delete image;
 
  } else {
 
    QPrinter pdf(QPrinter::HighResolution);
 
    pdf.setOutputFileName(fname);
 
    pdf.setOutputFormat(QPrinter::PdfFormat);
 
    QPainter painter(&pdf);
 
    canvas.render(&painter, QRectF(), QRectF(-5000,-5000, 10000, 10000));
 

	
 
    cerr << "Rendering to printer\n";
 
  }
 
}
 

	
 
void MainBase::CutSAM() {
 
	
 
	mesh.CutAwaySAM();
 
	
 
void MainBase::CutSAM()
 
{
 
  mesh.CutAwaySAM();
 
}
 

	
 
/* finis */
src/mainbase.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _MAINBASE_H_
 
#define _MAINBASE_H_
 

	
 
#include <QGraphicsScene>
 
#include <qpixmap.h>
 
#include <q3picture.h>
 
#include <qpainter.h>
 
#include <qwidget.h>
 
#include <iostream>
 
#include <QGraphicsItem>
 
#include <QPrinter>
 
#include "mesh.h"
 
#include "warning.h"
 

	
 
using namespace std;
 

	
 
/*! Implement these functions in your main application */
 
class MainBase  {
 

	
 
 public:
 
  MainBase(QGraphicsScene &c, Mesh &m) : mesh(m), canvas(c) {
 
    
 
 MainBase(QGraphicsScene &c, Mesh &m) : mesh(m), canvas(c) {
 

	
 
    // Standard options for batch version
 
    showcentersp =  false;
 
    showmeshp =  false;
 
    showbordercellp =  false;
 
    shownodenumbersp =  false;
 
    showcellnumbersp =  false;
 
    showcellsaxesp = false;
 
    showcellstrainp =  false;
 
    movieframesp = true;
 
    showboundaryonlyp =  false;
 
    showwallsp =  false;
 
    showfluxesp = false;
 
    dynamicscellsp = true;
 
    showtooltipsp = false;
 
    hidecellsp = false;
 
  }
 
    virtual ~MainBase() {};
 
    
 
    virtual double TimeStep();
 
    virtual void Init(char *leaffile=0);
 
    
 
    virtual bool ShowCentersP(void) {return showcentersp;}
 
    virtual bool ShowMeshP(void) {return showmeshp; }
 
    virtual bool ShowBorderCellsP(void) {return showbordercellp; }
 
    virtual bool PausedP(void) {return false; }
 
    virtual bool ShowNodeNumbersP(void) {return shownodenumbersp; }
 
    virtual bool ShowCellNumbersP(void) {return showcellnumbersp;}
 
    virtual bool ShowCellAxesP(void) {return showcellsaxesp;}
 
    virtual bool ShowCellStrainP(void) {return showcellstrainp;}
 
    virtual bool MovieFramesP(void) {return movieframesp;}
 
    virtual bool ShowBoundaryOnlyP(void) {return showboundaryonlyp;}
 
    virtual bool ShowToolTipsP(void) {return showtooltipsp;}
 
    virtual bool ShowWallsP(void) {return showwallsp;}
 
    virtual bool ShowApoplastsP(void) { return showapoplastsp;}
 
    virtual bool ShowFluxesP(void) { return showfluxesp; }
 
    virtual bool DynamicCellsP(void) { return dynamicscellsp; }
 
    virtual void FitCanvasToWindow() {};
 
    virtual void FitLeafToCanvas() {};
 
    virtual bool HideCellsP(void) { return hidecellsp; }
 
    virtual void clear(void) {
 
      QList<QGraphicsItem *> list = canvas.items();
 
      QList<QGraphicsItem *>::Iterator it = list.begin();
 
      for (; it != list.end(); ++it) {
 
	if ( *it )
 
	  delete *it;
 
      }
 
    };
 
    virtual void XMLReadSettings(xmlNode *settings);
 
    virtual double getFluxArrowsize(void) { return 10.;}
 
    
 
    void Save(const char *fname, const char *format, int sizex=640, int sizey=480);
 
    void CutSAM(void);
 
	
 
    void Plot(int resize_stride=10);
 
  virtual ~MainBase() {};
 

	
 
  virtual double TimeStep();
 
  virtual void Init(char *leaffile=0);
 

	
 
    virtual void UserMessage(QString message, int timeout = 0) {
 
      timeout = 0; // merely to obviate 'warning unused parameter' message
 
      cerr << message.toAscii().constData() << endl;
 
  virtual bool ShowCentersP(void) {return showcentersp;}
 
  virtual bool ShowMeshP(void) {return showmeshp; }
 
  virtual bool ShowBorderCellsP(void) {return showbordercellp; }
 
  virtual bool PausedP(void) {return false; }
 
  virtual bool ShowNodeNumbersP(void) {return shownodenumbersp; }
 
  virtual bool ShowCellNumbersP(void) {return showcellnumbersp;}
 
  virtual bool ShowCellAxesP(void) {return showcellsaxesp;}
 
  virtual bool ShowCellStrainP(void) {return showcellstrainp;}
 
  virtual bool MovieFramesP(void) {return movieframesp;}
 
  virtual bool ShowBoundaryOnlyP(void) {return showboundaryonlyp;}
 
  virtual bool ShowToolTipsP(void) {return showtooltipsp;}
 
  virtual bool ShowWallsP(void) {return showwallsp;}
 
  virtual bool ShowApoplastsP(void) { return showapoplastsp;}
 
  virtual bool ShowFluxesP(void) { return showfluxesp; }
 
  virtual bool DynamicCellsP(void) { return dynamicscellsp; }
 
  virtual void FitCanvasToWindow() {};
 
  virtual void FitLeafToCanvas() {};
 
  virtual bool HideCellsP(void) { return hidecellsp; }
 
  virtual void clear(void) {
 
    QList<QGraphicsItem *> list = canvas.items();
 
    QList<QGraphicsItem *>::Iterator it = list.begin();
 
    for (; it != list.end(); ++it) {
 
      if ( *it )
 
	delete *it;
 
    }
 
    Mesh &mesh;
 
	
 
 protected:
 
    QGraphicsScene &canvas;
 
    virtual xmlNode *XMLSettingsTree(void) const;
 
  };
 
  virtual void XMLReadSettings(xmlNode *settings);
 
  virtual double getFluxArrowsize(void) { return 10.;}
 

	
 
  void Save(const char *fname, const char *format, int sizex=640, int sizey=480);
 
  void CutSAM(void);
 

	
 
  void Plot(int resize_stride=10);
 

	
 
  virtual void UserMessage(QString message, int timeout = 0) {
 
    timeout = 0; // merely to obviate 'warning unused parameter' message
 
    cerr << message.toAscii().constData() << endl;
 
  }
 
  Mesh &mesh;
 

	
 
 protected:
 
    bool showcentersp;
 
    bool showmeshp;
 
    bool showbordercellp;
 
    bool shownodenumbersp;
 
    bool showcellnumbersp;
 
    bool showcellsaxesp;
 
    bool showcellstrainp;
 
    bool movieframesp;
 
    bool showboundaryonlyp;
 
    bool showwallsp;
 
    bool showapoplastsp;
 
    bool showfluxesp;
 
    bool dynamicscellsp;
 
    bool showtooltipsp;
 
    bool hidecellsp;
 
  QGraphicsScene &canvas;
 
  virtual xmlNode *XMLSettingsTree(void) const;
 

	
 
 protected:
 
  bool showcentersp;
 
  bool showmeshp;
 
  bool showbordercellp;
 
  bool shownodenumbersp;
 
  bool showcellnumbersp;
 
  bool showcellsaxesp;
 
  bool showcellstrainp;
 
  bool movieframesp;
 
  bool showboundaryonlyp;
 
  bool showwallsp;
 
  bool showapoplastsp;
 
  bool showfluxesp;
 
  bool dynamicscellsp;
 
  bool showtooltipsp;
 
  bool hidecellsp;
 
};
 

	
 
//#include <qapplication.h>
 
#define TIMESTEP double MainBase::TimeStep(void)
 
#define INIT void MainBase::Init(char *leaffile)
 

	
 
#endif
 

	
 
/* finis */
src/matrix.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include <ostream>
 
#include <cmath>
 
#include "vector.h"
 
#include "matrix.h"
 
#include "tiny.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
Matrix::Matrix(const Vector &c1, const Vector &c2, const Vector &c3) {
 
  
 

	
 
  Alloc();
 

	
 
  mat[0][0]=c1.x; mat[0][1]=c2.x; mat[0][2]=c3.x;
 
  mat[1][0]=c1.y; mat[1][1]=c2.y; mat[1][2]=c3.y;
 
  mat[2][0]=c1.z; mat[2][1]=c2.z; mat[2][2]=c3.z;
 

	
 
    
 
}
 

	
 
void Matrix::Alloc(void) {
 

	
 
void Matrix::Alloc(void)
 
{
 
  // constructor
 
  mat = new double*[3];
 
  mat[0] = new double[9];
 
  for (int i=1;i<3;i++)
 
    mat[i]=mat[i-1]+3;
 
  
 
}
 

	
 
Matrix::~Matrix() {
 
 
 
Matrix::~Matrix()
 
{
 
  // destructor
 
  delete[] mat[0];
 
  delete[] mat;
 
}
 

	
 
Matrix::Matrix(void) {
 
  
 
Matrix::Matrix(void)
 
{
 
  // constructor
 
  Alloc();
 

	
 
  // clear matrix
 
  for (int i=0;i<9;i++) {
 
    mat[0][i]=0.;
 
  }
 
 
 
}
 

	
 
Matrix::Matrix(const Matrix &source) {
 
 
 
Matrix::Matrix(const Matrix &source)
 
{
 
  // copy constructor
 
  Alloc();
 
  
 

	
 
  for (int i=0;i<9;i++) {
 
    mat[0][i]=source.mat[0][i];
 
  }
 
  
 
}
 

	
 

	
 
void Matrix::operator=(const Matrix &source) {
 
  
 
void Matrix::operator=(const Matrix &source)
 
{
 
  // assignment
 
  
 

	
 
  // don't assign to self
 
  if (this==&source) return;
 
  
 

	
 
  // copy 
 
  for (int i=0;i<9;i++)
 
    mat[0][i]=source.mat[0][i];
 
  
 
}
 

	
 

	
 
void Matrix::print(ostream *os) {
 
  
 
  *os << "{ { " << mat[0][0] << "," << mat[0][1] << "," << mat[0][2] << "},{" << mat[1][0] << "," << mat[1][1] << "," << mat[1][2] << "},{" << mat[2][0] << "," << mat[2][1] << "," << mat[2][2] << "} }";
 

	
 
void Matrix::print(ostream *os)
 
{
 
  *os << "{ { " << mat[0][0] << "," << mat[0][1] << "," << mat[0][2] 
 
      << "},{" << mat[1][0] << "," << mat[1][1] << "," << mat[1][2] 
 
      << "},{" << mat[2][0] << "," << mat[2][1] << "," << mat[2][2] << "} }";
 
}
 

	
 
ostream &operator<<(ostream &os, Matrix &v) {
 
  v.print(&os);
 
  return os;
 
}
 

	
 

	
 
Vector Matrix::operator*(const Vector &v) const {
 
  
 
Vector Matrix::operator*(const Vector &v) const
 
{
 
  // matrix * vector
 
  Vector result;
 
  
 

	
 
  result.x = mat[0][0]*v.x+mat[0][1]*v.y+mat[0][2]*v.z;
 
  result.y = mat[1][0]*v.x+mat[1][1]*v.y+mat[1][2]*v.z;
 
  result.z = mat[2][0]*v.x+mat[2][1]*v.y+mat[2][2]*v.z;
 
  
 

	
 
  return result;
 
  
 
  
 
}
 

	
 

	
 
bool Matrix::operator==(Matrix &m) const {
 
   
 
bool Matrix::operator==(Matrix &m) const
 
{
 
  for (int i=0;i<9;i++) {
 
    if ((mat[0][i]-m.mat[0][i])>TINY)
 
      return false;
 
  }
 
  return true;
 
  
 
}
 

	
 
double Matrix::Det(void) const {
 
  
 
double Matrix::Det(void) const
 
{
 
  return 
 
    - mat[0][2]*mat[0][4]*mat[0][6]
 
    + mat[0][1]*mat[0][5]*mat[0][6] 
 
    + mat[0][2]*mat[0][3]*mat[0][7]
 
    - mat[0][0]*mat[0][5]*mat[0][7]
 
    - mat[0][1]*mat[0][3]*mat[0][8]
 
    + mat[0][0]*mat[0][4]*mat[0][8];
 

	
 
}
 

	
 
Matrix Matrix::Inverse(void) const {
 
  
 
Matrix Matrix::Inverse(void) const
 
{
 

	
 
  // return the Inverse of this matrix
 
  double rd=1./Det(); // Reciproce Det;
 
  Matrix inverse;
 
  inverse.mat[0][0]=rd*(-mat[0][5]*mat[0][7]+mat[0][4]*mat[0][8]);
 
  inverse.mat[0][1]=rd*( mat[0][2]*mat[0][7]-mat[0][1]*mat[0][8]);
 
  inverse.mat[0][2]=rd*(-mat[0][2]*mat[0][4]+mat[0][1]*mat[0][5]);
 
  inverse.mat[0][3]=rd*( mat[0][5]*mat[0][6]-mat[0][3]*mat[0][8]);
 
  inverse.mat[0][4]=rd*(-mat[0][2]*mat[0][6]+mat[0][0]*mat[0][8]);
 
  inverse.mat[0][5]=rd*( mat[0][2]*mat[0][3]-mat[0][0]*mat[0][5]);
 
  inverse.mat[0][6]=rd*(-mat[0][4]*mat[0][6]+mat[0][3]*mat[0][7]);
 
  inverse.mat[0][7]=rd*( mat[0][1]*mat[0][6]-mat[0][0]*mat[0][7]);
 
  inverse.mat[0][8]=rd*(-mat[0][1]*mat[0][3]+mat[0][0]*mat[0][4]);
 
  
 

	
 
  return inverse;
 
}
 

	
 
void Matrix::Rot2D(double theta) { 
 
  
 
void Matrix::Rot2D(double theta)
 
{ 
 
  // make this matrix a rotation matrix over theta
 
  // see http://mathworld.wolfram.com/RotationMatrix.html
 
 
 

	
 
  mat[0][0] = cos(theta); mat[0][1]=sin(theta);
 
  mat[1][0] = -sin(theta); mat[1][1]=cos(theta);
 
  mat[0][2] = mat[1][2] = mat[2][0] = mat[2][1] = mat[2][2] = 0.;
 
}
 

	
 
}
 
/* finis */
src/matrix.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _MATRIX_H_
 
#define _MATRIX_H_
 

	
 
// three by three matrix (mostly for changes of basis of the vector object)
 
class Vector;
 

	
 
class Matrix {
 

	
 
public:
 
 public:
 
  Matrix(const Vector &v1,const Vector &v2, const Vector &v3); // constructor
 
  Matrix(void);
 
  ~Matrix(); // destructor
 

	
 
  void print(ostream *os);
 
  Matrix(const Matrix &source); // copy constructor
 
  void operator=(const Matrix &source); // assignment operator
 
  
 

	
 
  Vector operator*(const Vector &v) const; // matrix * vector
 
  bool operator==(Matrix &v) const; // comparison
 
  double Det(void) const; // gives the "determinant" (| m |) of m
 
  Matrix Inverse(void) const; // gives the inverse of m
 
  void Rot2D(double theta); // make a matrix doing a 2D rotation over theta
 
  // data members 
 
  double **mat;
 

	
 
private:
 
 private:
 

	
 
  void Alloc(void);
 
};
 

	
 
ostream &operator<<(ostream &os, Matrix &v);
 

	
 
#endif
 

	
 
/* finis */
src/maxmin.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _MAXMIN_H_
 
#define _MAXMIN_H_
 

	
 
#include <cmath>
 

	
 
inline double FMAX(double a, double b) { return a>b ? a : b; }
 
inline double FMIN(double a, double b) { return a<b ? a : b; }
 
inline double SIGN(double a, double b) { return b>=0.0 ? fabs(a) : -fabs(a); }
 

	
 
#endif
 

	
 
/* finis */
src/mesh.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include <algorithm>
 
#include <vector>
 
#include <sstream>
 
#include <cstdlib>
 
//#include <cerrno>
 
#include <cstring>
 
#include <numeric>
 
#include <functional>
 
#include <fstream>
 
#include <QPair>
 
#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 <QDebug>
 
#include <set>
 
#include <iostream>
 
#include <iterator>
 

	
 
static const std::string _module_id("$Id$");
 

	
 
extern Parameter par;
 

	
 
void Mesh::AddNodeToCellAtIndex(Cell *c, Node *n, Node *nb1, Node *nb2, list<Node *>::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<Cell *>::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;c<Cell::NChem();c++) {
 
    cell->SetChemical(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 <Cell *> current_cells = cells;
 
    for (vector<Cell *>::iterator j=current_cells.begin();
 
	 j!=current_cells.end();j++) {
 
      (*j)->DivideOverAxis(axis);
 
    }
 
    axis=axis.Perp2D();
 
    
 

	
 
  }
 
  
 

	
 
  IncreaseCellCapacityIfNecessary();
 
  
 

	
 
  axis=axis.Perp2D();
 
  
 

	
 
  vector <Cell *> current_cells = cells;
 
  for (vector<Cell *>::iterator j=current_cells.begin();
 
	 j!=current_cells.end();j++) {
 
   (*j)->DivideOverAxis(axis);
 
 }
 

	
 
  
 
 double sum_l=0; int n_l=0;
 
       j!=current_cells.end();j++) {
 
    (*j)->DivideOverAxis(axis);
 
  }
 

	
 

	
 
  double sum_l=0; int n_l=0;
 
  for (list<Node *>::const_iterator i=cell->nodes.begin();
 
       i!=cell->nodes.end();
 
       i++) {
 
    list<Node *>::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;i<nnodes;i++) {
 
    
 

	
 
    double angle=2*Pi*(i/(double)nnodes);
 
    double x=xc+ra*cos(angle)*cos(rotation) - rb*sin(angle)*sin(rotation);
 
    double y=yc+ra*cos(angle)*sin(rotation) + rb*sin(angle)*cos(rotation);
 
    
 
    
 

	
 

	
 
    Node *n=AddNode(new Node(x,y,0));
 
    n->boundary = true;
 
    
 

	
 
  } 
 
  
 

	
 
  for (int i=0;i<nnodes;i++) {
 
    
 

	
 
    AddNodeToCell(c,
 
		  nodes[first_node + i],
 
		  nodes[first_node+ (nnodes+i-1)%nnodes],
 
		  nodes[first_node+ (i + 1)%nnodes]);
 
    AddNodeToCell(boundary_polygon,
 
		  nodes[first_node + i],
 
		  nodes[first_node+ (nnodes+i-1)%nnodes],
 
		  nodes[first_node+ (i + 1)%nnodes]);
 
  }
 
  
 

	
 
  boundary_polygon->m = 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<int>::iterator nb;
 
  for (list<int>::iterator i=c->nodes.begin();
 
       i!=c->nodes.end();
 
       i++) {
 
    
 
    nb = i; nb++;
 
    if (nb==c->nodes.end()) {
 
      for (list<int>::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()) {
 
      }
 
      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) );
 
  }*/
 
  
 
      } 
 
      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<nnodes;i++) {
 
    
 

	
 
    double angle=2*Pi*(i/(double)nnodes);
 
    double x=xc+ra*cos(angle)*cos(rotation) - rb*sin(angle)*sin(rotation);
 
    double y=yc+ra*cos(angle)*sin(rotation) + rb*sin(angle)*cos(rotation);
 
    
 
    
 

	
 

	
 
    Node *n=AddNode(new Node(x,y,0));
 
    
 

	
 
    /* if (angle > 1.25*Pi && angle < 1.75*Pi ) {
 
      n.sam = true;
 
      }*/
 
    
 
       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<Node *>::reverse_iterator it_n1=circle->nodes.rbegin();
 
  for (int i=0;i<nnodes/2;i++)
 
    it_n1++;
 
  it_n1--;
 
  
 

	
 
  list<Node *>::reverse_iterator it_n2=--circle->nodes.rend();
 
  /* for (int i=0;i<n/2;i++)
 
     it_n2++;*/
 
  
 

	
 
  Cell *petiole=AddCell(new Cell());
 

	
 
  Node *n1 = *it_n1;
 
  Node *n2 = *it_n2;
 
  
 

	
 
  Node *n3=AddNode( new Node ( *n2 + Vector( 0, pet_length, 0) ) );
 
  Node *n4=AddNode( new Node ( *n1 + Vector( 0, pet_length, 0) ) );
 

	
 
  n3->boundary=true;
 
  n4->boundary=true;
 

	
 
  AddNodeToCell(petiole, *it_n1, 
 
		n4,
 
		nodes[(*it_n2)->Index() 
 
		      + (( (*it_n1)->Index() - (*it_n2)->Index() )-1+nnodes)%nnodes]);
 

	
 
  
 
		
 

	
 

	
 
  list<Node *>::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);
 

	
 
  
 
  #ifdef QDEBUG  
 

	
 
#ifdef QDEBUG  
 
  qDebug() << circle << endl;
 
  qDebug() << petiole << endl;
 
  #endif
 
  
 
#endif
 

	
 
  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;i<nnodes;i++) {
 
    
 

	
 
    if (nodes[(first_node + i)]->owners.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<Node *>::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<Node *>::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<Cell *>::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();
 
  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<Node *>::iterator i=nodes.begin();
 
		 i!=nodes.end();
 
		 i++) {
 
		delete *i;
 
	}
 
	
 
	nodes.clear();
 

	
 
  // clear nodes
 
  for (vector<Node *>::iterator i=nodes.begin();
 
       i!=nodes.end();
 
       i++) {
 
    delete *i;
 
  }
 

	
 
  nodes.clear();
 
  Node::nnodes=0;
 

	
 
  node_insertion_queue.clear();
 
  // Clear NodeSets
 
  for (vector<NodeSet *>::iterator i=node_sets.begin();
 
       i!=node_sets.end();
 
       i++) {
 
    delete *i;
 
  }
 

	
 
  node_sets.clear();
 
  time = 0;
 

	
 
  // clear cells
 

	
 
  for (vector<Cell *>::iterator i=cells.begin();
 
       i!=cells.end();
 
       i++) {
 
    delete *i;
 
  }
 

	
 
  cells.clear();
 
  Cell::NCells() = 0;
 

	
 
  delete boundary_polygon;
 

	
 
  // Clear walls
 
  for (list<Wall *>::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;
 
	
 
	node_insertion_queue.clear();
 
	// Clear NodeSets
 
	for (vector<NodeSet *>::iterator i=node_sets.begin();
 
		 i!=node_sets.end();
 
		 i++) {
 
		delete *i;
 
	}
 
	
 
	node_sets.clear();
 
	time = 0;
 
	
 
	// clear cells
 
	
 
	for (vector<Cell *>::iterator i=cells.begin();
 
		 i!=cells.end();
 
		 i++) {
 
		delete *i;
 
	}
 
	
 

	
 
	cells.clear();
 
	Cell::NCells() = 0;
 
	
 
	delete boundary_polygon;
 
	
 
	// Clear walls
 
	for (list<Wall *>::iterator i=walls.begin();
 
		 i!=walls.end();
 
		 i++) {
 
		delete *i;
 
	}
 
	
 
	walls.clear();
 
	WallBase::nwalls = 0;
 
	//tmp_walls->clear();
 
	
 
	nodes.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;
 
	 */
 

	
 
	#ifdef QDEBUG
 
	qDebug() << "cells.size() = " << cells.size() << endl;
 
	qDebug << "walls.size() = " << walls.size() << endl;
 
	qDebug << "nodes.size() = " << nodes.size() << endl;
 
        #endif
 
	node_insertion_queue.empty();
 

	
 
	cerr << "Meshed cleared: cells: " << cells.size() << ", nodes: " << nodes.size() << endl;
 
  */
 

	
 
#ifdef QDEBUG
 
  qDebug() << "cells.size() = " << cells.size() << endl;
 
  qDebug << "walls.size() = " << walls.size() << endl;
 
  qDebug << "nodes.size() = " << nodes.size() << endl;
 
#endif
 
}
 

	
 
double Mesh::DisplaceNodes(void) {
 

	
 
  MyUrand r(shuffled_nodes.size());
 
  random_shuffle(shuffled_nodes.begin(),shuffled_nodes.end(),r);
 
  
 

	
 
  double sum_dh=0;
 
  
 

	
 
  list<DeltaIntgrl> delta_intgrl_list;
 
  
 

	
 
  for_each( node_sets.begin(), node_sets.end(), mem_fun( &NodeSet::ResetDone ) );
 
  
 

	
 
  for (vector<Node *>::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);
 
    
 
      // 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<Neighbor>::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 = 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) );
 
		
 

	
 
	  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<Neighbor>::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);
 
	    sum_dh+=c->cell->Displace(rx,ry,0);
 
	  }
 
	}
 
      } else {
 
	
 
    
 

	
 

	
 
	if (dh<-sum_stiff || RANDOM()<exp((-dh-sum_stiff)/par.T)) {
 
	  
 

	
 
	  // update areas of cells
 
	  list<DeltaIntgrl>::const_iterator di_it = delta_intgrl_list.begin();
 
	  for (list<Neighbor>::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<Neighbor>::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;
 
    
 
  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<Node *>::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<Neighbor> 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<Neighbor>(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<Neighbor>(debug_stream, " "));
 
  //  debug_stream << endl;
 
  
 

	
 
  // the duplicates in this list indicate cells owning this edge  
 
  list<Neighbor>::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<Node *>::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 the position of the edge's first node in cell c...
 
      list<Node *>::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<Neighbor>::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
 
  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 *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<Cell *>::iterator i=cells.begin();
 
       i!=cells.end();
 
       i++) {
 
  
 

	
 
    sum+=(*i)->chem[ch];
 
  }
 
  return sum;
 

	
 
}
 

	
 

	
 

	
 
void Mesh::CleanUpCellNodeLists(void) {
 
  
 

	
 
  typedef vector <vector<Cell *>::iterator> CellItVect;
 
  
 

	
 
  CellItVect cellstoberemoved;
 
  vector<int> cellind;
 
  
 

	
 
  // Start of by removing all stale walls.
 
  //DeleteLooseWalls();
 
  // collect all dead cells that need to be removed from the simulation
 
  for (vector<Cell *>::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<Wall *>::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<Wall *>::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<int>::reverse_iterator j=cellind.rbegin();
 
       j!=cellind.rend();
 
       j++) {
 

	
 
    for (vector<Cell *>::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 <vector<Node *>::iterator> NodeItVect;
 
  
 

	
 
  NodeItVect nodestoberemoved;
 
  vector<int> nodeindlist;
 
 
 

	
 
  // collect iterators and indices of dead nodes
 
  for (vector<Node *>::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<int>::reverse_iterator j=nodeindlist.rbegin();
 
       j!=nodeindlist.rend();
 
       j++) {
 

	
 
    for (vector<Node *>::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<Wall *>::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<Node *>::iterator i=nodes.begin();
 
       i!=nodes.end();
 
       i++) {
 
    
 

	
 
    (*i)->owners.clear();
 
  }
 
  
 

	
 
  for (vector<Cell *>::iterator i=cells.begin();
 
       i!=cells.end();
 
       i++) {
 

	
 
    (*i)->ConstructConnections();
 

	
 
  }
 

	
 
  boundary_polygon->ConstructConnections();
 
  
 

	
 
  /* for (list<Wall *>::iterator w=walls.begin();
 
       w!=walls.end();
 
       w++) {
 
    delete *w;    
 
  }
 
  
 
  walls.clear(); 
 
  cerr << "Cleared walls\n"; 
 
  for (vector<Cell *>::iterator i=cells.begin();
 
       i!=cells.end();
 
       i++) {
 
    
 
    (*i)->ConstructWalls();
 
  }
 
     w!=walls.end();
 
     w++) {
 
     delete *w;    
 
     }
 

	
 
     walls.clear(); 
 
     cerr << "Cleared walls\n"; 
 
     for (vector<Cell *>::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();
 
  
 
  #ifdef QDEBUG
 

	
 
#ifdef QDEBUG
 
  qDebug() << "Before Apoptose" << endl;
 
  #endif
 
#endif
 

	
 
  TestIllegalWalls();
 
  for (vector<Cell *>::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();
 
    }
 
  }
 

	
 
  #ifdef QDEBUG
 
#ifdef QDEBUG
 
  qDebug() << "Before CleanUpCellNodeLists" << endl;
 
  #endif
 
#endif
 
  TestIllegalWalls();
 
  
 

	
 
  CleanUpCellNodeLists();
 

	
 
}
 

	
 
void Mesh::CutAwaySAM(void) {
 

	
 
  for (vector<Cell *>::iterator i=cells.begin();
 
       i!=cells.end();
 
       i++) {
 
    
 

	
 
    if( (*i)->Boundary() == Cell::SAM ) {
 

	
 
	(*i)->Apoptose();
 
      (*i)->Apoptose();
 
    }
 
  }
 

	
 
  TestIllegalWalls();
 
  
 

	
 
  CleanUpCellNodeLists();
 

	
 

	
 
}
 
void Mesh::TestIllegalWalls(void) {
 

	
 
  for (list<Wall *>::iterator w = walls.begin();
 
       w!=walls.end();
 
       w++) {
 
    if ((*w)->IllegalP() ) {
 
      #ifdef QDEBUG
 
#ifdef QDEBUG
 
      qDebug() << "Wall " << **w << " is illegal." << endl;
 
      #endif
 
#endif
 
    }
 
  }
 

	
 
}
 

	
 

	
 

	
 
class node_owners_eq : public unary_function<Node, bool> {
 
  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<int> original_boundary_nodes, repaired_boundary_nodes;
 
  vector<int> 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<Neighbor>::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<Node *>::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<Node *>::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<Wall *>::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
 
  qDebug() << "Repaired Boundary Polygon node indices: ";
 
  foreach (Node* node, boundary_polygon->nodes){
 
    qDebug() << node->Index() << " " ;
 
  }
 
  qDebug() << endl ;
 

	
 
  #ifdef _undefined_
 
#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
 

	
 
#endif
 
}
 

	
 

	
 
Node* Mesh::findNextBoundaryNode(Node* boundary_node) {
 
  bool found_next_boundary_node = false;
 
  Node *next_boundary_node = NULL;
 
  set<int> boundary_node_owners; // This is a list of the current boundary node's owners' Ids
 
  vector<int> neighborIds; // A list of the current boundary node's owners' 2nd neighbor Ids
 
  vector<set<int> *>  nodeOwners; // A vector of set pointers where each set contains the owner Ids of the nodes in the neighborIds list.
 
  vector<int> intersection; // set intersection result
 

	
 
  // The next boundary node is that which has only one owner in common with the current boundary node
 
  for (list<Neighbor>::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<int> *owners = new set<int>; // 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<int>::iterator itt = neighborIds.begin();
 
  vector<set<int> *>::iterator it = nodeOwners.begin();
 

	
 
  #ifdef QDEBUG  
 
#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
 
#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  
 
#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
 
#endif
 

	
 
    if (intersection.size() == 1){
 
      found_next_boundary_node = true;
 
      vector<Node *>::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  
 
#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
 
#endif
 

	
 
      break;
 
    }
 
  }
 

	
 
  #ifdef QDEBUG  
 
#ifdef QDEBUG  
 
  if (!found_next_boundary_node) {
 
    qDebug() << "OOPS! Didn't find the next boundrary node!" << endl;
 
  }
 
  #endif
 
#endif
 

	
 
  return next_boundary_node;
 
}
 

	
 

	
 
void Mesh::CleanUpWalls(void) {
 
  for (list<Wall *>::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<Node *>::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<Wall>(cerr, "\n"), deref_ptr<Wall> );
 

	
 

	
 
  transform ( walls.begin(), walls.end(), ostream_iterator<Wall>(cerr, "\n"), deref_ptr<Wall> );
 
}
 

	
 
#include <QString>
 
//#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;
 
		
 
    
 
	}
 
  
 
  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;i<m->NEqs();i++) {
 
       of << x << " " << dxdy[i] << endl;
 
       }
 
       of.close();
 
      QString fname("derivs%1.dat");
 

	
 
      ofstream of(fname.arg(++c).ascii());
 

	
 
      for (int i=0;i<m->NEqs();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<Cell *>::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<Wall *>::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<scale_y ? scale_x:scale_y;
 
  
 

	
 
  Cell::SetMagnification(factor); // smallest of scale_x and scale_y
 
  
 

	
 
  double offset_x = (width/Cell::Magnification()-(bbur.x-bbll.x))/2.;  
 
  double offset_y = (height/Cell::Magnification()-(bbur.y-bbll.y))/2.;
 
  
 

	
 
  Cell::setOffset(offset_x, offset_y);
 
  
 

	
 
  }*/
 

	
 

	
 

	
 
void Mesh::CleanChemicals(const vector<double> &clean_chem) {
 
	
 
	if (clean_chem.size()!=(unsigned)Cell::NChem()) {
 
		throw "Run time error in Mesh::CleanChemicals: size of clean_chem should be equal to Cell::NChem()";
 
	}
 
	for (vector<Cell *>::iterator c=cells.begin();
 
		 c!=cells.end();
 
		 c++) {
 
		
 
		for (int i=0;i<Cell::NChem();i++) {
 
			(*c)->SetChemical(i,clean_chem[i]);
 
		}
 
		(*c)->SetNewChemToChem();
 
		
 
	}
 
	
 

	
 

	
 
  if (clean_chem.size()!=(unsigned)Cell::NChem()) {
 
    throw "Run time error in Mesh::CleanChemicals: size of clean_chem should be equal to Cell::NChem()";
 
  }
 
  for (vector<Cell *>::iterator c=cells.begin();
 
       c!=cells.end();
 
       c++) {
 

	
 
    for (int i=0;i<Cell::NChem();i++) {
 
      (*c)->SetChemical(i,clean_chem[i]);
 
    }
 
    (*c)->SetNewChemToChem();
 

	
 
  }
 
}
 

	
 

	
 
void Mesh::CleanTransporters(const vector<double> &clean_transporters) {
 
	
 
	if (clean_transporters.size()!=(unsigned)Cell::NChem()) {
 
		throw "Run time error in Mesh::CleanTransporters: size ofclean_transporters should be equal to Cell::NChem()";
 
	}
 

	
 
	
 
	// clean transporters
 
	for (list<Wall *>::iterator w=walls.begin();
 
		 w!=walls.end();
 
		 w++) {
 
		
 
		for (int i=0;i<Cell::NChem();i++) {
 
			(*w)->setTransporters1(i,clean_transporters[i]); (*w)->setNewTransporters1(i,clean_transporters[i]);
 
			(*w)->setTransporters2(i,clean_transporters[i]); (*w)->setNewTransporters2(i,clean_transporters[i]);
 
		}
 
	}
 
	
 

	
 
  if (clean_transporters.size()!=(unsigned)Cell::NChem()) {
 
    throw "Run time error in Mesh::CleanTransporters: size ofclean_transporters should be equal to Cell::NChem()";
 
  }
 

	
 

	
 
  // clean transporters
 
  for (list<Wall *>::iterator w=walls.begin();
 
       w!=walls.end();
 
       w++) {
 

	
 
    for (int i=0;i<Cell::NChem();i++) {
 
      (*w)->setTransporters1(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<double> &max_chem, const vector<double> &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<Cell *>::iterator c=cells.begin();
 
       c!=cells.end();
 
       c++) {
 
    
 

	
 
    for (int i=0;i<Cell::NChem();i++) {
 
      (*c)->SetChemical(i,max_chem[i]*RANDOM());
 
    }
 
    (*c)->SetNewChemToChem();
 

	
 
  }
 

	
 
  // randomize transporters
 
  for (list<Wall *>::iterator w=walls.begin();
 
       w!=walls.end();
 
       w++) {
 
    
 

	
 
    for (int i=0;i<Cell::NChem();i++) {
 
      (*w)->setTransporters1(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<neqs;i++) { derivs[i]=0.;}
 
  
 

	
 
  // Layout of derivatives: cells [ chem1 ... chem n]  walls [ [ w1(chem 1) ... w1(chem n) ] [ w2(chem 1) ... w2(chem n) ] ]
 

	
 
  int i=0;
 

	
 
  for (vector<Cell *>::iterator c=cells.begin();
 
       c!=cells.end();
 
       c++) {
 
    //(*cr)(*c, &(derivs[i]));
 
	  plugin->CellDynamics(*c, &(derivs[i]));
 
	  i+=nchems;
 
    plugin->CellDynamics(*c, &(derivs[i]));
 
    i+=nchems;
 
  }
 
	
 

	
 
  for (list<Wall *>::iterator w=walls.begin();
 
       w!=walls.end();
 
       w++) {
 
   // (*wr)(*w, &(derivs[i]), &(derivs[i+nchems]));
 
	  plugin->WallDynamics(*w,  &(derivs[i]), &(derivs[i+nchems]));
 
    // (*wr)(*w, &(derivs[i]), &(derivs[i+nchems]));
 
    plugin->WallDynamics(*w,  &(derivs[i]), &(derivs[i+nchems]));
 
    // Transport function adds to derivatives of cell chemicals
 
	  double *dchem_c1 = &(derivs[(*w)->c1->Index() * nchems]);
 
	  double *dchem_c2 = &(derivs[(*w)->c2->Index() * nchems]);
 
	  //plugin->CelltoCellTransport(*w, &(derivs[(*w)->c1->Index() * nchems]),
 
							//	  &(derivs[(*w)->c2->Index() * nchems]));
 
	  // quick fix: dummy values to prevent end user from writing into outer space and causing a crash :-)
 
	  // start here if you want to implement chemical input/output into environment over boundaries
 
	  double dummy1, dummy2;
 
	  if ((*w)->c1->Index()<0) { // tests if c1 is the boundary pol
 
		  dchem_c1 = &dummy1;
 
	  }
 
	  if ((*w)->c2->Index()<0) {
 
		  dchem_c2 = &dummy2;
 
	  }
 
	  plugin->CelltoCellTransport(*w, dchem_c1, dchem_c2); 
 
								  
 
	  //(*tf)(*w, &(derivs[(*w)->c1->Index() * nchems]),
 
      //&(derivs[(*w)->c2->Index() * nchems] ) );
 
    double *dchem_c1 = &(derivs[(*w)->c1->Index() * nchems]);
 
    double *dchem_c2 = &(derivs[(*w)->c2->Index() * nchems]);
 
    //plugin->CelltoCellTransport(*w, &(derivs[(*w)->c1->Index() * nchems]),
 
    //	  &(derivs[(*w)->c2->Index() * nchems]));
 
    // quick fix: dummy values to prevent end user from writing into outer space and causing a crash :-)
 
    // start here if you want to implement chemical input/output into environment over boundaries
 
    double dummy1, dummy2;
 
    if ((*w)->c1->Index()<0) { // tests if c1 is the boundary pol
 
      dchem_c1 = &dummy1;
 
    }
 
    if ((*w)->c2->Index()<0) {
 
      dchem_c2 = &dummy2;
 
    }
 
    plugin->CelltoCellTransport(*w, dchem_c1, dchem_c2); 
 

	
 
    //(*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<Cell *>::iterator c=cells.begin();
 
       c!=cells.end();
 
       c++) {
 
    for (int ch=0;ch<nchems;ch++) {
 
      (*c)->SetChemical(ch, y[i+ch]);
 
    }
 
    if ( !(emit_count%stride)) {
 
      (*c)->EmitValues(x);
 
    }
 
    i+=nchems;
 
  }
 
  
 

	
 
  for (list<Wall *>::iterator w=walls.begin();
 
       w!=walls.end();
 
       w++) {
 
    
 

	
 
    for (int ch=0;ch<nchems;ch++) {
 
      (*w)->setTransporters1(ch,y[i+ch]);
 
    }
 
    i+=nchems;
 
    
 

	
 
    for (int ch=0;ch<nchems;ch++) {
 
      (*w)->setTransporters2(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<Cell *>::iterator c=cells.begin();
 
       c!=cells.end();
 
       c++) {
 
    for (int ch=0;ch<nchems;ch++) {
 
      values[i+ch]=(*c)->Chemical(ch);
 
    }
 
    i+=nchems;
 
  }
 
  
 

	
 
  for (list<Wall *>::iterator w=walls.begin();
 
       w!=walls.end();
 
       w++) {
 
    
 

	
 
    for (int ch=0;ch<nchems;ch++) {
 
      values[i+ch]=(*w)->Transporters1(ch);
 
    }
 
    i+=nchems;
 
    
 

	
 
    for (int ch=0;ch<nchems;ch++) {
 
      values[i+ch]=(*w)->Transporters2(ch);
 
    }
 
    i+=nchems;
 

	
 
  }
 

	
 
  return values;
 
}
 

	
 
void Mesh::DrawNodes(QGraphicsScene *c) const {
 
  
 

	
 
  for (vector<Node *>::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<Wall *>::const_iterator w=walls.begin();
 
       w!=walls.end();
 
       w++) {
 
    sum_prot += (*w)->Transporters1(ch);
 
    sum_prot += (*w)->Transporters2(ch);
 
  }
 

	
 
  // At cells
 
  for (vector<Cell *>::const_iterator c=cells.begin();
 
       c!=cells.end();
 
       c++) {
 
    
 

	
 
    sum_prot += (*c)->Chemical(ch);
 
  }
 
  
 

	
 
  return sum_prot;
 

	
 
}
 

	
 
void Mesh::SettoInitVals(void) {
 
  
 

	
 
  vector<double> clean_chem(Cell::NChem());
 
  vector<double> clean_transporters(Cell::NChem());
 
  
 

	
 
  for (int i=0;i<Cell::NChem();i++) {
 
    clean_transporters[i]=0.;
 
    clean_chem[i]=par.initval[i];
 
  }
 

	
 
  // Amount of PIN1
 
  //clean_chem[1] = 0.;
 
  
 
	CleanChemicals(clean_chem);
 
	CleanTransporters(clean_transporters);
 

	
 

	
 
  CleanChemicals(clean_chem);
 
  CleanTransporters(clean_transporters);
 
}
 

	
 
string Mesh::getTimeHours(void) const {
 
	int hours = (int)(time / 3600);
 
	int mins = (int)((time - hours * 3600)/60);
 
	int secs = (int)((time - hours * 3600 - mins * 60));
 
	ostringstream tstr;
 
	tstr << hours << " h " << mins << " m " << secs << " s";
 
	return tstr.str();
 
  int hours = (int)(time / 3600);
 
  int mins = (int)((time - hours * 3600)/60);
 
  int secs = (int)((time - hours * 3600 - mins * 60));
 
  ostringstream tstr;
 
  tstr << hours << " h " << mins << " m " << secs << " s";
 
  return tstr.str();
 
}
 

	
 
QVector<qreal> Mesh::VertexAngles(void) {
 
	QVector<qreal> angles;
 
	for (vector<Node *>::const_iterator n=nodes.begin();
 
		 n!=nodes.end();
 
		 n++) {
 
		if ((*n)->Value()>2 && !(*n)->BoundaryP() ) {
 
			angles+=(*n)->NeighbourAngles();
 
		}
 
	}
 
	return angles;
 
  QVector<qreal> angles;
 
  for (vector<Node *>::const_iterator n=nodes.begin();
 
       n!=nodes.end();
 
       n++) {
 
    if ((*n)->Value()>2 && !(*n)->BoundaryP() ) {
 
      angles+=(*n)->NeighbourAngles();
 
    }
 
  }
 
  return angles;
 
}
 

	
 
QVector< QPair<qreal,int> > Mesh::VertexAnglesValues(void) {
 

	
 
	QVector< QPair<qreal,int> > anglesvalues;
 
	for (vector<Node *>::const_iterator n=nodes.begin();
 
		 n!=nodes.end();
 
		 n++) {
 
		if ((*n)->Value()>2 && !(*n)->BoundaryP() ) {
 
			
 
			QVector<qreal> angles = (*n)->NeighbourAngles();
 
			int value_vertex = angles.size();
 
			for (QVector<qreal>::ConstIterator i=angles.begin();
 
				 i!=angles.end();
 
				 i++) {
 
				
 
				anglesvalues += QPair< qreal, int > (*i, value_vertex);
 
			}
 
		}
 
	}
 
	return anglesvalues;
 
  QVector< QPair<qreal,int> > anglesvalues;
 
  for (vector<Node *>::const_iterator n=nodes.begin();
 
       n!=nodes.end();
 
       n++) {
 
    if ((*n)->Value()>2 && !(*n)->BoundaryP() ) {
 

	
 
      QVector<qreal> angles = (*n)->NeighbourAngles();
 
      int value_vertex = angles.size();
 
      for (QVector<qreal>::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<Node *>::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<NodeSet *>::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<Cell *>::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<Wall *>::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;
 
#ifdef QDEBUG
 
  qDebug() << "Freeing nodes" << endl;
 
#endif
 
  for (vector<Node *>::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<NodeSet *>::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<Cell *>::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<Wall *>::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<Cell::NChem(); c++) {
 
		circle.SetChemical(c, 0.);
 
	}
 
  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<Cell::NChem(); c++) {
 
    circle.SetChemical(c, 0.);
 
  }
 
}
 

	
 

	
src/mesh.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
// Cell derives from Vector, where Vector is simply used as a Vertex
 

	
 
#ifndef _MESH_H_
 
#define _MESH_H_
 

	
 
#include <vector>
 
#include <algorithm>
 
#include <queue>
 
#include <iterator>
 
#include <functional>
 
#ifdef QTGRAPHICS
 
#include <QGraphicsScene>
 
#endif
 
#include "cell.h"
 
#include "node.h"
 
#include "simplugin.h"
 
#include <QVector>
 
#include <QPair>
 
#include <QDebug>
 

	
 
using namespace std;
 
// new queue which rejects duplicate elements
 
template<class T, class C = deque<T> > class unique_queue : public queue<T,C> {
 
	
 
public:
 
	typedef typename C::value_type value_type;
 
	// reimplements push: reject element if it exists already
 
	void push(const value_type &x) {
 
		if (find (queue<T,C>::c.begin(),queue<T,C>::c.end(),x)==queue<T,C>::c.end()) {
 
			queue<T,C>::c.push_back(x);
 
		}
 
	}
 
	void clear(void) {
 
		queue<T,C>::c.clear();
 
	}
 

	
 
 public:
 
 typedef typename C::value_type value_type;
 
 // reimplements push: reject element if it exists already
 
 void push(const value_type &x) {
 
   if (find (queue<T,C>::c.begin(),queue<T,C>::c.end(),x)==queue<T,C>::c.end()) {
 
     queue<T,C>::c.push_back(x);
 
   }
 
 }
 
 void clear(void) {
 
   queue<T,C>::c.clear();
 
 }
 
};
 

	
 
template<class P> P& deref_ptr ( P *obj) { return *obj; }
 

	
 

	
 
class Mesh {
 
	
 
	friend class Cell;
 
	friend class Node;
 
	friend class FigureEditor;
 
	
 
public: 
 
	Mesh(void) {
 
		// Make sure the reserved value is large enough if a cell is added
 
		// in "Divide" when the capacity is insufficient, "cells" might be
 
		// relocated including the current Cell (i.e. the value of *this)
 
		// calling "Mesh::IncreaseCapacityIfNecessary" (from another
 
		// object than Cell, e.g. Mesh) before entering Divide will solve
 
		// this issue (solved now).
 
		cells.reserve(2);
 
		nodes.reserve(500);
 
		
 
		time = 0.;
 
		plugin = 0;
 
	};
 
	~Mesh(void) {
 
		delete boundary_polygon;
 
	};
 
	
 
	void Clean(void);
 
	Cell &EllipticCell(double xc, double yc, double ra, double rb, int nnodes=10, double rotation=0);
 
	Cell &CircularCell(double xc, double yc, double r, int nnodes=10) {
 
		return EllipticCell(xc, yc, r, r, nnodes, 0);
 
	}
 
	Cell &LeafPrimordium(int n, double pet_length);
 
	Cell &LeafPrimordium2(int n);
 
	Cell *RectangularCell(const Vector ll, const Vector ur, double rotation = 0);
 
	void CellFiles(const Vector ll, const Vector ur);
 
	
 
	inline Cell &getCell(int i) {
 
		if ((unsigned)i<cells.size())
 
			return *cells[i];
 
		else {
 
                        #ifdef QDEBUG
 
                        qDebug() << i << endl;
 
                        qDebug() << "size is " << cells.size() << endl;
 
                        #endif
 
			abort();
 
		}
 
	}
 
	
 
	inline Node &getNode(int i) {
 
		return *nodes[i];    
 
	}
 
	
 
	//double Diffusion(void);
 
	inline int size(void) {
 
		return cells.size();
 
	}
 
	inline int nnodes(void) {
 
		return nodes.size();
 
	}
 

	
 
  friend class Cell;
 
  friend class Node;
 
  friend class FigureEditor;
 

	
 
 public: 
 
  Mesh(void) {
 
    // Make sure the reserved value is large enough if a cell is added
 
    // in "Divide" when the capacity is insufficient, "cells" might be
 
    // relocated including the current Cell (i.e. the value of *this)
 
    // calling "Mesh::IncreaseCapacityIfNecessary" (from another
 
    // object than Cell, e.g. Mesh) before entering Divide will solve
 
    // this issue (solved now).
 
    cells.reserve(2);
 
    nodes.reserve(500);
 

	
 
    time = 0.;
 
    plugin = 0;
 
  };
 
  ~Mesh(void) {
 
    delete boundary_polygon;
 
  };
 

	
 
  void Clean(void);
 
  Cell &EllipticCell(double xc, double yc, double ra, double rb, int nnodes=10, double rotation=0);
 
  Cell &CircularCell(double xc, double yc, double r, int nnodes=10) {
 
    return EllipticCell(xc, yc, r, r, nnodes, 0);
 
  }
 
  Cell &LeafPrimordium(int n, double pet_length);
 
  Cell &LeafPrimordium2(int n);
 
  Cell *RectangularCell(const Vector ll, const Vector ur, double rotation = 0);
 
  void CellFiles(const Vector ll, const Vector ur);
 

	
 
  inline Cell &getCell(int i) {
 
    if ((unsigned)i<cells.size())
 
      return *cells[i];
 
    else {
 
#ifdef QDEBUG
 
      qDebug() << i << endl;
 
      qDebug() << "size is " << cells.size() << endl;
 
#endif
 
      abort();
 
    }
 
  }
 

	
 
  inline Node &getNode(int i) {
 
    return *nodes[i];    
 
  }
 

	
 
  //double Diffusion(void);
 
  inline int size(void) {
 
    return cells.size();
 
  }
 
  inline int nnodes(void) {
 
    return nodes.size();
 
  }
 

	
 
  template<class Op> void LoopCells(Op f) {
 
    for (vector <Cell *>::iterator i=cells.begin();
 
	 i!=cells.end();
 
	 i++) {
 
      f(**i);
 
    }
 
  }
 

	
 
  template<class Op> void LoopWalls(Op f) {
 
    for (list <Wall *>::iterator i=walls.begin();
 
	 i!=walls.end();
 
	 i++) {
 
      f(**i);
 
    }
 
  }
 

	
 
	template<class Op> void LoopCells(Op f) {
 
		for (vector <Cell *>::iterator i=cells.begin();
 
			 i!=cells.end();
 
			 i++) {
 
			f(**i);
 
		}
 
	}
 
	
 
	template<class Op> void LoopWalls(Op f) {
 
		for (list <Wall *>::iterator i=walls.begin();
 
			 i!=walls.end();
 
			 i++) {
 
			f(**i);
 
		}
 
	}
 
	
 
	// if the amount of cells might increase, during looping, use this template
 
	template<class Op> void LoopCurrentCells(Op f) {
 
		vector<Cell *> current_cells = cells;
 
		for (vector <Cell *>::iterator i=current_cells.begin();
 
			 i!=current_cells.end();
 
			 i++) {
 
			f(**i);
 
			
 
		}
 
	}
 
	
 
	template<class Op> void LoopNodes(Op f) {
 
		for (vector<Node *>::iterator i=nodes.begin();
 
			 i!=nodes.end();
 
			 i++) {
 
			f(**i); 
 
		}
 
	}
 
	
 
	template<class Op> void RandomlyLoopNodes(Op f) {
 
		
 
		MyUrand r(shuffled_nodes.size());
 
		random_shuffle(shuffled_nodes.begin(),shuffled_nodes.end(),r);
 
		
 
		for (vector<Node *>::const_iterator i=shuffled_nodes.begin();
 
			 i!=shuffled_nodes.end();
 
			 i++) {
 
			f(*shuffled_nodes[*i]);
 
		}
 
		
 
	}
 
	
 
	template<class Op> void RandomlyLoopCells(Op f) {
 
		
 
		MyUrand r(shuffled_cells.size());
 
		random_shuffle(shuffled_cells.begin(),shuffled_cells.end(),r);
 
		
 
		for (vector<Cell *>::const_iterator i=shuffled_cells.begin();
 
			 i!=shuffled_cells.end();
 
			 i++) {
 
			f(*shuffled_cells[*i]);
 
		}
 
		
 
		
 
	}
 
	
 
	template<class Op1, class Op2> void LoopCells(Op1 f, Op2 &g) {
 
		for (vector<Cell *>::iterator i=cells.begin();
 
			 i!=cells.end();
 
			 i++) {
 
			f(**i,g); 
 
		}
 
	}
 
	
 
	template<class Op1, class Op2, class Op3> void LoopCells(Op1 f, Op2 &g, Op3 &h) {
 
		for (vector<Cell *>::iterator i=cells.begin();
 
			 i!=cells.end();
 
			 i++) {
 
			f(**i,g,h); 
 
		}
 
	}
 
	
 
	void DoCellHouseKeeping(void) {
 
		vector<Cell *> current_cells = cells;
 
		for (vector<Cell *>::iterator i = current_cells.begin();
 
			 i != current_cells.end();
 
			 i ++) {
 
			plugin->CellHouseKeeping(*i);
 
			
 
			// Call functions of Cell that cannot be called from CellBase, including Division
 
			if ((*i)->flag_for_divide) {
 
				if ((*i)->division_axis) {
 
					(*i)->DivideOverAxis(*(*i)->division_axis);
 
					delete (*i)->division_axis;
 
					(*i)->division_axis = 0;
 
				} else {
 
					(*i)->Divide();
 
				}
 
				(*i)->flag_for_divide=false;
 
			}
 
		}
 
	}
 
	
 
	// Apply "f" to cell i
 
	// i.e. this is an adapter which allows you to call a function
 
	// operating on Cell on its numeric index index
 
	template<class Op> void cell_index_adapter(Op f,int i) {
 
		f(cells[i]);
 
	}
 
	
 
	double DisplaceNodes(void);
 
	
 
	void BoundingBox(Vector &LowerLeft, Vector &UpperRight);
 
	int NEqs(void) {     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;
 
		
 
		return neqs;
 
  // if the amount of cells might increase, during looping, use this template
 
  template<class Op> void LoopCurrentCells(Op f) {
 
    vector<Cell *> current_cells = cells;
 
    for (vector <Cell *>::iterator i=current_cells.begin();
 
	 i!=current_cells.end();
 
	 i++) {
 
      f(**i);
 

	
 
    }
 
  }
 

	
 
  template<class Op> void LoopNodes(Op f) {
 
    for (vector<Node *>::iterator i=nodes.begin();
 
	 i!=nodes.end();
 
	 i++) {
 
      f(**i); 
 
    }
 
  }
 

	
 
  template<class Op> void RandomlyLoopNodes(Op f) {
 

	
 
    MyUrand r(shuffled_nodes.size());
 
    random_shuffle(shuffled_nodes.begin(),shuffled_nodes.end(),r);
 

	
 
    for (vector<Node *>::const_iterator i=shuffled_nodes.begin();
 
	 i!=shuffled_nodes.end();
 
	 i++) {
 
      f(*shuffled_nodes[*i]);
 
    }
 
  }
 

	
 
  template<class Op> void RandomlyLoopCells(Op f) {
 

	
 
    MyUrand r(shuffled_cells.size());
 
    random_shuffle(shuffled_cells.begin(),shuffled_cells.end(),r);
 

	
 
    for (vector<Cell *>::const_iterator i=shuffled_cells.begin();
 
	 i!=shuffled_cells.end();
 
	 i++) {
 
      f(*shuffled_cells[*i]);
 
    }
 
  }
 

	
 
  template<class Op1, class Op2> void LoopCells(Op1 f, Op2 &g) {
 
    for (vector<Cell *>::iterator i=cells.begin();
 
	 i!=cells.end();
 
	 i++) {
 
      f(**i,g); 
 
    }
 
  }
 

	
 
  template<class Op1, class Op2, class Op3> void LoopCells(Op1 f, Op2 &g, Op3 &h) {
 
    for (vector<Cell *>::iterator i=cells.begin();
 
	 i!=cells.end();
 
	 i++) {
 
      f(**i,g,h); 
 
    }
 
  }
 

	
 
  void DoCellHouseKeeping(void) {
 
    vector<Cell *> current_cells = cells;
 
    for (vector<Cell *>::iterator i = current_cells.begin();
 
	 i != current_cells.end();
 
	 i ++) {
 
      plugin->CellHouseKeeping(*i);
 

	
 
      // Call functions of Cell that cannot be called from CellBase, including Division
 
      if ((*i)->flag_for_divide) {
 
	if ((*i)->division_axis) {
 
	  (*i)->DivideOverAxis(*(*i)->division_axis);
 
	  delete (*i)->division_axis;
 
	  (*i)->division_axis = 0;
 
	} else {
 
	  (*i)->Divide();
 
	}
 
	void IncreaseCellCapacityIfNecessary(void) {
 
		
 
		return;
 
		// cerr << "Entering Mesh::IncreaseCellCapacityIfNecessary \n";
 
		// make sure we always have enough space 
 
		// to have each cell divide at least once
 
		//
 
		// Note that we must do this, because Cell::Divide pushes a new Cell
 
		// onto Mesh::cells. As a result, Mesh::cells might be relocated 
 
		// if we are _within_ a Cell object: i.e. pointer "this" will be changed!!
 
		// 
 
		// An alternative solution could be to make "Mesh::cells" a list,
 
		// but this won't work because we need random access for 
 
		// the Monte Carlo algorithm.
 
		
 
		if (2*cells.size()>cells.capacity()) {
 
			cerr << "Increasing capacity to "  << 2*cells.capacity() << endl;
 
			cerr << "Current capacity is " << cells.capacity() << endl;
 
			cells.reserve(cells.capacity()*2);
 
		}
 
	}
 
	
 
	void ReserveMoreCells(int n) {
 
		if (nodes.size()+n>nodes.capacity()) {
 
			nodes.reserve(size()+n);
 
		}
 
	}
 
	double Area(void);
 
	double MeanArea(void) {
 
		double sum=0.;
 
		for (vector<Cell *>::const_iterator i=cells.begin();
 
			 i!=cells.end();
 
			 i++) {
 
			sum+=(*i)->Area();
 
		}
 
		return sum/(double)NCells();
 
	}
 
	
 
	void SetBaseArea(void);
 
	int NCells(void) const {
 
		return cells.size();
 
	}
 
	inline int NNodes(void) const {
 
		return nodes.size();
 
	}
 
	void PrintQueue(ostream &os) {
 
		while (!node_insertion_queue.empty()) {
 
			os << node_insertion_queue.front() << endl;
 
			node_insertion_queue.pop();
 
		}
 
	}
 
	
 
	void InsertNodes(void) {
 
		// insert the nodes in the insertion queue
 
		while (!node_insertion_queue.empty()) {
 
			
 
			//cerr << node_insertion_queue.front() << endl;
 
			InsertNode(node_insertion_queue.front());
 
			node_insertion_queue.pop();
 
		}
 
		
 
	}
 
	
 
	void Clear(); 
 
	
 
	void ReactDiffuse( double delta_t = 1 );
 
	double SumChemical(int ch);
 
	void SetChemical(int ch, double value) {
 
		for (vector<Cell *>::iterator c=cells.begin();
 
			 c!=cells.end();
 
			 c++) {
 
			(*c)->chem[ch]=value;
 
		}
 
	}
 
	
 
	// used for interacing with ODE-solvers (e.g. NRCRungeKutta)
 
	void setValues(double x, double *y);
 
	double *getValues(int *neqs);
 
	void Derivatives(double *derivs);
 
	(*i)->flag_for_divide=false;
 
      }
 
    }
 
  }
 

	
 
  // Apply "f" to cell i
 
  // i.e. this is an adapter which allows you to call a function
 
  // operating on Cell on its numeric index index
 
  template<class Op> void cell_index_adapter(Op f,int i) {
 
    f(cells[i]);
 
  }
 

	
 
  double DisplaceNodes(void);
 

	
 
  void BoundingBox(Vector &LowerLeft, Vector &UpperRight);
 
  int NEqs(void) {     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;
 

	
 
    return neqs;
 
  }
 
  void IncreaseCellCapacityIfNecessary(void) {
 

	
 
    return;
 
    // cerr << "Entering Mesh::IncreaseCellCapacityIfNecessary \n";
 
    // make sure we always have enough space 
 
    // to have each cell divide at least once
 
    //
 
    // Note that we must do this, because Cell::Divide pushes a new Cell
 
    // onto Mesh::cells. As a result, Mesh::cells might be relocated 
 
    // if we are _within_ a Cell object: i.e. pointer "this" will be changed!!
 
    // 
 
    // An alternative solution could be to make "Mesh::cells" a list,
 
    // but this won't work because we need random access for 
 
    // the Monte Carlo algorithm.
 

	
 
    if (2*cells.size()>cells.capacity()) {
 
      cerr << "Increasing capacity to "  << 2*cells.capacity() << endl;
 
      cerr << "Current capacity is " << cells.capacity() << endl;
 
      cells.reserve(cells.capacity()*2);
 
    }
 
  }
 

	
 
  void ReserveMoreCells(int n) {
 
    if (nodes.size()+n>nodes.capacity()) {
 
      nodes.reserve(size()+n);
 
    }
 
  }
 
  double Area(void);
 
  double MeanArea(void) {
 
    double sum=0.;
 
    for (vector<Cell *>::const_iterator i=cells.begin();
 
	 i!=cells.end();
 
	 i++) {
 
      sum+=(*i)->Area();
 
    }
 
    return sum/(double)NCells();
 
  }
 

	
 
  void SetBaseArea(void);
 
  int NCells(void) const {
 
    return cells.size();
 
  }
 
  inline int NNodes(void) const {
 
    return nodes.size();
 
  }
 
  void PrintQueue(ostream &os) {
 
    while (!node_insertion_queue.empty()) {
 
      os << node_insertion_queue.front() << endl;
 
      node_insertion_queue.pop();
 
    }
 
  }
 

	
 
  void InsertNodes(void) {
 
    // insert the nodes in the insertion queue
 
    while (!node_insertion_queue.empty()) {
 

	
 
      //cerr << node_insertion_queue.front() << endl;
 
      InsertNode(node_insertion_queue.front());
 
      node_insertion_queue.pop();
 
    }
 

	
 
  }
 

	
 
  void Clear(); 
 

	
 
  void ReactDiffuse( double delta_t = 1 );
 
  double SumChemical(int ch);
 
  void SetChemical(int ch, double value) {
 
    for (vector<Cell *>::iterator c=cells.begin();
 
	 c!=cells.end();
 
	 c++) {
 
      (*c)->chem[ch]=value;
 
    }
 
  }
 

	
 
  // used for interacing with ODE-solvers (e.g. NRCRungeKutta)
 
  void setValues(double x, double *y);
 
  double *getValues(int *neqs);
 
  void Derivatives(double *derivs);
 
#ifdef QTGRAPHICS
 
	inline void DrawBoundary(QGraphicsScene *c) {
 
		boundary_polygon->Draw(c);
 
	}
 
	void DrawNodes(QGraphicsScene *c) const;
 
	
 
  inline void DrawBoundary(QGraphicsScene *c) {
 
    boundary_polygon->Draw(c);
 
  }
 
  void DrawNodes(QGraphicsScene *c) const;
 

	
 
#endif
 
	double max_chem;
 
	
 
	void XMLSave(const char *docname, xmlNode *settings=0) const;
 
	void XMLRead(const char *docname, xmlNode **settings=0, bool geometry = true, bool pars = true, bool simtime = true);
 
	void XMLReadPars(const xmlNode * root_node);
 
	void XMLReadGeometry(const xmlNode *root_node);
 
	void XMLReadSimtime(const xmlNode *root_node);
 
	void XMLReadNodes(xmlNode *cur);
 
	void XMLReadCells(xmlNode *cur);
 
	void XMLParseTree(const xmlNode * root_node);
 
	void XMLReadWalls(xmlNode *cur, vector<Wall *> *tmp_cells);
 
	void XMLReadWallsToCells(xmlNode *root, vector<Wall *> *tmp_walls);
 
	void XMLReadNodeSets(xmlNode *root);
 
	void XMLReadNodeSetsToNodes(xmlNode *root);
 
	void PerturbChem(int chemnum, double range);
 
	void CleanUpCellNodeLists(void);
 
	void CleanUpWalls(void);
 
	void CutAwayBelowLine( Vector startpoint, Vector endpoint );
 
	void CutAwaySAM(void);
 
	void RepairBoundaryPolygon(void);
 
	void Rotate(double angle, Vector center);
 
	void PrintWallList( void );
 
	void TestIllegalWalls(void);
 
	Vector FirstConcMoment(int chem);
 
	inline Vector Centroid(void) {
 
		return boundary_polygon->Centroid();
 
	}
 
	
 
	inline Vector Offset(void) {
 
		return boundary_polygon->Offset();
 
	}
 
	
 
	inline double Factor(void) {
 
		return boundary_polygon->Factor();
 
	}
 
	
 
	void DeleteLooseWalls(void);
 
	void FitLeafToCanvas(double width, double height);
 
	void AddNodeSet(NodeSet *node_set) {
 
		node_sets.push_back(node_set);
 
	}
 
	
 
	void CleanChemicals(const vector<double> &clean_chem);
 
	void CleanTransporters(const vector<double> &clean_transporters);
 
	void RandomizeChemicals(const vector<double> &max_chem, const vector<double> &max_transporters);
 
	inline double getTime(void) const { return time; }
 
	string getTimeHours(void) const; 
 
	inline void setTime(double t) { time = t; }
 
	double CalcProtCellsWalls(int ch) const;  
 
	void SettoInitVals(void);
 
	QVector<qreal> VertexAngles(void);
 
	QVector< QPair<qreal,int> > VertexAnglesValues(void);
 
	void SetSimPlugin(SimPluginInterface *new_plugin) {
 
		plugin=new_plugin;
 
	}
 
	QString ModelID(void) { return plugin?plugin->ModelID():QString("undefined"); }
 
	void StandardInit(void);	
 
  double max_chem;
 

	
 
  void XMLSave(const char *docname, xmlNode *settings=0) const;
 
  void XMLRead(const char *docname, xmlNode **settings=0, bool geometry = true, bool pars = true, bool simtime = true);
 
  void XMLReadPars(const xmlNode * root_node);
 
  void XMLReadGeometry(const xmlNode *root_node);
 
  void XMLReadSimtime(const xmlNode *root_node);
 
  void XMLReadNodes(xmlNode *cur);
 
  void XMLReadCells(xmlNode *cur);
 
  void XMLParseTree(const xmlNode * root_node);
 
  void XMLReadWalls(xmlNode *cur, vector<Wall *> *tmp_cells);
 
  void XMLReadWallsToCells(xmlNode *root, vector<Wall *> *tmp_walls);
 
  void XMLReadNodeSets(xmlNode *root);
 
  void XMLReadNodeSetsToNodes(xmlNode *root);
 
  void PerturbChem(int chemnum, double range);
 
  void CleanUpCellNodeLists(void);
 
  void CleanUpWalls(void);
 
  void CutAwayBelowLine( Vector startpoint, Vector endpoint );
 
  void CutAwaySAM(void);
 
  void RepairBoundaryPolygon(void);
 
  void Rotate(double angle, Vector center);
 
  void PrintWallList( void );
 
  void TestIllegalWalls(void);
 
  Vector FirstConcMoment(int chem);
 
  inline Vector Centroid(void) {
 
    return boundary_polygon->Centroid();
 
  }
 

	
 
  inline Vector Offset(void) {
 
    return boundary_polygon->Offset();
 
  }
 

	
 
  inline double Factor(void) {
 
    return boundary_polygon->Factor();
 
  }
 

	
 
  void DeleteLooseWalls(void);
 
  void FitLeafToCanvas(double width, double height);
 
  void AddNodeSet(NodeSet *node_set) {
 
    node_sets.push_back(node_set);
 
  }
 

	
 
	Node* findNextBoundaryNode(Node*);
 
  void CleanChemicals(const vector<double> &clean_chem);
 
  void CleanTransporters(const vector<double> &clean_transporters);
 
  void RandomizeChemicals(const vector<double> &max_chem, const vector<double> &max_transporters);
 
  inline double getTime(void) const { return time; }
 
  string getTimeHours(void) const; 
 
  inline void setTime(double t) { time = t; }
 
  double CalcProtCellsWalls(int ch) const;  
 
  void SettoInitVals(void);
 
  QVector<qreal> VertexAngles(void);
 
  QVector< QPair<qreal,int> > VertexAnglesValues(void);
 
  void SetSimPlugin(SimPluginInterface *new_plugin) {
 
    plugin=new_plugin;
 
  }
 
  QString ModelID(void) { return plugin?plugin->ModelID():QString("undefined"); }
 
  void StandardInit(void);	
 

	
 
  Node* findNextBoundaryNode(Node*);
 

	
 
 private:
 

	
 
private:
 
	
 
	// Data members
 
	vector<Cell *> cells;
 
	vector<Node *> nodes;
 
	list<Wall *> walls; // we need to erase elements from this container frequently, hence a list.
 
public:
 
	vector<NodeSet *> node_sets;
 
private:
 
	vector<Node *> shuffled_nodes;
 
	vector<Cell *> shuffled_cells;
 
	unique_queue<Edge> node_insertion_queue;
 
	BoundaryPolygon *boundary_polygon;
 
	double time;
 
	SimPluginInterface *plugin;
 
	
 
	// Private member functions
 
	void AddNodeToCell(Cell *c, Node *n, Node *nb1 , Node *nb2);
 
	void AddNodeToCellAtIndex(Cell *c, Node *n, Node *nb1 , Node *nb2, list<Node *>::iterator ins_pos);
 
	void InsertNode(Edge &e);
 
	inline Node *AddNode(Node *n) {
 
		nodes.push_back(n);
 
		shuffled_nodes.push_back(n);
 
		n->m=this;
 
		return n;
 
	}
 
	
 
	inline Cell *AddCell(Cell *c) {
 
		cells.push_back(c);
 
		shuffled_cells.push_back(c);
 
		//cerr << "Shuffled cell indices:  ";
 
		/*copy(shuffled_cells.begin(),shuffled_cells.end(),ostream_iterator<int>(cerr," "));
 
		 cerr << endl;*/
 
		c->m=this;
 
		return c;
 
	}
 
	
 
	void CircumCircle(double x1,double y1,double x2,double y2,double x3,double y3,
 
					  double *xc,double *yc,double *r);
 
  // Data members
 
  vector<Cell *> cells;
 
  vector<Node *> nodes;
 
  list<Wall *> walls; // we need to erase elements from this container frequently, hence a list.
 
 public:
 
  vector<NodeSet *> node_sets;
 
 private:
 
  vector<Node *> shuffled_nodes;
 
  vector<Cell *> shuffled_cells;
 
  unique_queue<Edge> node_insertion_queue;
 
  BoundaryPolygon *boundary_polygon;
 
  double time;
 
  SimPluginInterface *plugin;
 

	
 
  // Private member functions
 
  void AddNodeToCell(Cell *c, Node *n, Node *nb1 , Node *nb2);
 
  void AddNodeToCellAtIndex(Cell *c, Node *n, Node *nb1 , Node *nb2, list<Node *>::iterator ins_pos);
 
  void InsertNode(Edge &e);
 
  inline Node *AddNode(Node *n) {
 
    nodes.push_back(n);
 
    shuffled_nodes.push_back(n);
 
    n->m=this;
 
    return n;
 
  }
 

	
 
  inline Cell *AddCell(Cell *c) {
 
    cells.push_back(c);
 
    shuffled_cells.push_back(c);
 
    //cerr << "Shuffled cell indices:  ";
 
    /*copy(shuffled_cells.begin(),shuffled_cells.end(),ostream_iterator<int>(cerr," "));
 
      cerr << endl;*/
 
    c->m=this;
 
    return c;
 
  }
 

	
 
  void CircumCircle(double x1,double y1,double x2,double y2,double x3,double y3,
 
		    double *xc,double *yc,double *r);
 
};
 
#endif
 

	
 
/* finis */
src/miscq.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include <QString>
 
#include <QStringList>
 

	
 
static const std::string _module_id("$Id$");
 

	
 
// Returns the extension of a filename
 
QString getExtension(const QString fn) {
 
  
 
QString getExtension(const QString fn)
 
{
 
  // split on dots
 
  QStringList parts = fn.split(".");
 
  
 

	
 
  // return last part, this should be the extension
 
  return QString(parts.last());
 
  
 
}
 

	
 
/* finis */
src/miscq.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _MISCQ_h_
 
#define _MISCQ_h_
 

	
 
#include <QString>
 

	
 
// Miscellaneous helper functions, using Qt
 

	
 
QString getExtension(const QString fn);
 

	
 
#endif
 

	
 
/* finis */
src/modelcatalogue.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include "modelcatalogue.h"
 
#include <QVariant>
 

	
 
static const std::string _module_id("$Id$");
 

	
 
ModelCatalogue::ModelCatalogue(Mesh *_mesh, Main *_mainwin, const char *model=0) {
 
	mesh = _mesh;
 
	mainwin = _mainwin;
 
	if (model) {
 
	  cerr << "Loading model: " << model << endl;
 
		LoadPlugin(model);
 
	} else {
 
	  cerr << "Loading all models." << endl;
 
		LoadPlugins();
 
	}
 
  mesh = _mesh;
 
  mainwin = _mainwin;
 
  if (model) {
 
    cerr << "Loading model: " << model << endl;
 
    LoadPlugin(model);
 
  } else {
 
    cerr << "Loading all models." << endl;
 
    LoadPlugins();
 
  }
 
}
 

	
 
void ModelCatalogue::LoadPlugins() {
 
	
 
	QDir pluginDir(QApplication::applicationDirPath()); 
 
	QStringList plugin_filters; // filter for plugins, i.e "*.dll", "*.dylib"
 

	
 
  QDir pluginDir(QApplication::applicationDirPath()); 
 
  QStringList plugin_filters; // filter for plugins, i.e "*.dll", "*.dylib"
 
#if defined(Q_OS_WIN) 
 
	if (pluginDir.dirName().toLower() =="debug" 
 
		||pluginDir.dirName().toLower() =="release") 
 
		pluginDir.cdUp(); 
 
	plugin_filters << "*.dll";
 
	#elif defined(Q_OS_MAC) 
 
	if (pluginDir.dirName() =="MacOS"){ 
 
		pluginDir.cdUp(); 
 
		pluginDir.cdUp(); 
 
		pluginDir.cdUp(); 
 
	} 
 
	plugin_filters << "*.dylib";
 
  if (pluginDir.dirName().toLower() =="debug" 
 
      ||pluginDir.dirName().toLower() =="release") 
 
    pluginDir.cdUp(); 
 
  plugin_filters << "*.dll";
 
#elif defined(Q_OS_MAC) 
 
  if (pluginDir.dirName() =="MacOS"){ 
 
    pluginDir.cdUp(); 
 
    pluginDir.cdUp(); 
 
    pluginDir.cdUp(); 
 
  } 
 
  plugin_filters << "*.dylib";
 
#endif 
 
	pluginDir.setNameFilters(plugin_filters);
 
  pluginDir.setNameFilters(plugin_filters);
 

	
 
	if (!pluginDir.cd("models")) {
 
		MyWarning::error("Directory 'models' not found!");
 
	}
 
	
 
	
 
	//QVector<SimPluginInterface *> plugins;
 
	foreach (QString fileName, pluginDir.entryList(QDir::Files)){ 
 
		QPluginLoader loader(pluginDir.absoluteFilePath(fileName)); 
 
		if (SimPluginInterface *plugin = 
 
			qobject_cast<SimPluginInterface *>(loader.instance())) {
 
			models.append(plugin); 
 
		} else {
 
			cerr << loader.errorString().toStdString().c_str() << endl;
 
			MyWarning::warning("Could not load model %s: %s",fileName.toStdString().c_str(), loader.errorString().toStdString().c_str());
 
		}
 
	}
 
	if (models.size()==0) {
 
		MyWarning::error("No models could be loaded.");
 
	}
 
  if (!pluginDir.cd("models")) {
 
    MyWarning::error("Directory 'models' not found!");
 
  }
 

	
 

	
 
  //QVector<SimPluginInterface *> plugins;
 
  foreach (QString fileName, pluginDir.entryList(QDir::Files)){ 
 
    QPluginLoader loader(pluginDir.absoluteFilePath(fileName)); 
 
    if (SimPluginInterface *plugin = 
 
	qobject_cast<SimPluginInterface *>(loader.instance())) {
 
      models.append(plugin); 
 
    } else {
 
      cerr << loader.errorString().toStdString().c_str() << endl;
 
      MyWarning::warning("Could not load model %s: %s",fileName.toStdString().c_str(), loader.errorString().toStdString().c_str());
 
    }
 
  }
 
  if (models.size()==0) {
 
    MyWarning::error("No models could be loaded.");
 
  }
 
}
 

	
 
void ModelCatalogue::LoadPlugin(const char *model) {
 

	
 
	
 

	
 
  QDir pluginDir(QApplication::applicationDirPath()); 
 
  QStringList plugin_filters; // filter for plugins, i.e "*.dll", "*.dylib"
 
	
 
	
 

	
 

	
 
#if defined(Q_OS_WIN) 
 
  if (pluginDir.dirName().toLower() =="debug" 
 
      ||pluginDir.dirName().toLower() =="release") 
 
    pluginDir.cdUp(); 
 
  //plugin_filters << "*.dll";
 
#elif defined(Q_OS_MAC) 
 
  if (pluginDir.dirName() =="MacOS"){ 
 
    pluginDir.cdUp(); 
 
    pluginDir.cdUp(); 
 
    pluginDir.cdUp(); 
 
  } 
 
  //plugin_filters << "*.dylib";
 
#endif
 
  plugin_filters << model;
 
  pluginDir.setNameFilters(plugin_filters);
 
	
 

	
 
  if (!pluginDir.cd("models")) {
 
    MyWarning::error("Directory 'models' not found!");
 
  }
 
	
 

	
 
  QStringList modelnames=pluginDir.entryList(QDir::Files);
 
  if (modelnames.empty()) {
 
    MyWarning::error("Model %s not found - hint: do not include path in filename.",model);
 
  }
 
  foreach (QString fileName, modelnames){ 
 
    QPluginLoader loader(pluginDir.absoluteFilePath(fileName)); 
 
		
 

	
 
    if (SimPluginInterface *plugin = 
 
	qobject_cast<SimPluginInterface *>(loader.instance())) {
 
      models.append(plugin); 
 
      //MyWarning::warning("Successfully loaded model %s",fileName.toStdString().c_str());
 
    } else {
 
      MyWarning::warning("Could not load plugin %s",fileName.toStdString().c_str());
 
    }
 
  }
 
}
 

	
 
void ModelCatalogue::InstallFirstModel() {
 
	InstallModel(models[0]);
 
  InstallModel(models[0]);
 
}
 
void ModelCatalogue::PopulateModelMenu() {
 
	foreach (SimPluginInterface *model, models) {
 
		QAction *modelaction = new QAction(model->ModelID(), mainwin); 
 
		QVariant data;
 
		data.setValue(model);
 
		modelaction->setData(data);
 
		mainwin->modelmenu->addAction(modelaction);
 
		
 
	}
 
	connect(mainwin->modelmenu, SIGNAL(triggered(QAction *)), this, SLOT(InstallModel(QAction *)) );
 
  foreach (SimPluginInterface *model, models) {
 
    QAction *modelaction = new QAction(model->ModelID(), mainwin); 
 
    QVariant data;
 
    data.setValue(model);
 
    modelaction->setData(data);
 
    mainwin->modelmenu->addAction(modelaction);
 

	
 
  }
 
  connect(mainwin->modelmenu, SIGNAL(triggered(QAction *)), this, SLOT(InstallModel(QAction *)) );
 
}	
 

	
 
void ModelCatalogue::InstallModel(QAction *modelaction) {
 
	QVariant data = modelaction->data();
 
	SimPluginInterface *model = data.value<SimPluginInterface *>();
 
	cerr << "You chose model " << model->ModelID().toStdString() << "!\n";
 
	mesh->Clean();
 
	InstallModel(model);
 
  QVariant data = modelaction->data();
 
  SimPluginInterface *model = data.value<SimPluginInterface *>();
 
  cerr << "You chose model " << model->ModelID().toStdString() << "!\n";
 
  mesh->Clean();
 
  InstallModel(model);
 
}
 

	
 
void ModelCatalogue::InstallModel(SimPluginInterface *plugin) {
 
	
 

	
 
  // make sure both main and plugin use the same static datamembers (ncells, nchems...)
 
  plugin->SetCellsStaticDatamembers(CellBase::GetStaticDataMemberPointer());
 
	
 

	
 
  mesh->SetSimPlugin(plugin);
 
  Cell::SetNChem(plugin->NChem());
 
  plugin->SetParameters(&par);
 

	
 
  if (mainwin) {
 
    mainwin->RefreshInfoBar();
 
    mainwin->Init(0);
 
  }
 
}
src/modelcatalogue.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#ifndef _MODELCATALOGUE_H_
 
#define _MODELCATALOGUE_H_
 

	
 
#include "warning.h"
 
#include "cell.h"
 
#include "mesh.h"
 
#include "simplugin.h"
 
#include "canvas.h"
 
#include <QPluginLoader>
 
#include <Q3PopupMenu>
 
#include <QAction>
 
#include <QDir>
 
#include <QApplication>
 
#include <QObject>
 
#include <QAction>
 
#include <QMenu>
 

	
 
class ModelCatalogue : public QObject {
 
Q_OBJECT
 
public:
 
	ModelCatalogue(Mesh *mesh, Main *mainwin, const char *model); 	
 
	void LoadPlugins(); 
 
	void LoadPlugin(const char *model);
 
	
 
	void InstallFirstModel();
 
	void PopulateModelMenu();	
 
  Q_OBJECT
 
    public:
 
  ModelCatalogue(Mesh *mesh, Main *mainwin, const char *model); 	
 
  void LoadPlugins(); 
 
  void LoadPlugin(const char *model);
 

	
 
public slots:
 
	void InstallModel(SimPluginInterface *model);	
 
	void InstallModel(QAction *modelaction);
 
private:
 
	QVector<SimPluginInterface *> models;
 
	Mesh *mesh;
 
	Main *mainwin;
 
  void InstallFirstModel();
 
  void PopulateModelMenu();	
 

	
 
  public slots:
 
  void InstallModel(SimPluginInterface *model);	
 
  void InstallModel(QAction *modelaction);
 
 private:
 
  QVector<SimPluginInterface *> models;
 
  Mesh *mesh;
 
  Main *mainwin;
 
};
 
#endif
src/modelelement.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _MODELELEMENT_H_
 
#define _MODELELEMENT_H_
 

	
 
#include "vector.h"
 

	
 
// pure virtual base class for all model elements
 

	
 
class ModelElement {
 
  
 

	
 
 public:
 
  virtual void Displace(void) {};
 
  virtual ~ModelElement() {};
 
};
 
#endif
src/node.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include <sstream>
 
#ifdef QTGRAPHICS
 
#include <qstring.h>
 
#include <QGraphicsSimpleTextItem>
 
#endif
 
#include "node.h" 
 
#include "cell.h"
 
#include "mesh.h"
 
#include "random.h"
 
#include "parameter.h"
 
#include "sqr.h"
 
#include "pi.h"
 
#include "warning.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
extern Parameter par;
 

	
 
int Node::nnodes=0;
 
double Node::target_length=1;
 

	
 
ostream &Edge::print(ostream &os) const {
 
  return os << "{ " << first->Index() << ", " << second->Index() << " }";
 
}
 

	
 
ostream &Neighbor::print(ostream &os) const {
 
  
 

	
 
  os << " {" << cell->Index() << " " << nb1->Index() << " " << nb2->Index() << "}";
 
  return os;
 

	
 
}
 

	
 
ostream &operator<<(ostream &os, const Neighbor &n) {
 
  n.print(os);
 
  return os;
 
}
 
 
 

	
 

	
 
Node::Node(void) : Vector() {
 

	
 
Node::Node(void) : Vector()
 
{
 
  index=(nnodes++);
 
  node_set =0;
 
  fixed=false;
 
  boundary=false;
 
  sam=false;
 
  dead=false;
 
}
 

	
 
Node::Node(int ind) : Vector() {
 
Node::Node(int ind) : Vector()
 
{
 
  node_set =0;
 
  index=ind;
 
  fixed=false;
 
  boundary=false;
 
  sam=false;
 
  dead=false;
 
}
 

	
 
Node::Node(const Vector &src) : Vector(src) {
 

	
 
Node::Node(const Vector &src) : Vector(src)
 
{
 
  node_set = 0;
 
  index=(nnodes++);
 
  fixed=false;
 
  boundary=false;
 
  sam=false;
 
  dead = false;
 
}
 

	
 
Node::Node(double x,double y, double z) : Vector (x,y,z) {
 
  
 
Node::Node(double x,double y, double z) : Vector (x,y,z)
 
{
 
  node_set = 0;
 
  index=(nnodes++);
 
  fixed=false;
 
  boundary=false;
 
  sam=false;
 
  dead = false;
 
}
 

	
 
Node::Node(const Node &src) : Vector(src) {
 
  
 
Node::Node(const Node &src) : Vector(src)
 
{
 
  node_set=0;
 
  owners=src.owners;
 
  m=src.m;
 
  index=src.index;
 
  fixed = src.fixed;
 
  boundary = src.boundary;
 
  sam=src.sam;
 
  dead = src.dead;
 
}
 

	
 

	
 
Cell &Node::getCell(const Neighbor &i) {
 
Cell &Node::getCell(const Neighbor &i)
 
{
 
  return *i.getCell(); // use accessor!
 
}
 

	
 

	
 
ostream &Node::print(ostream &os) const {
 
  
 

	
 
  if (!dead) 
 
    os << "Node ";
 
  else
 
    os << "DEAD NODE ";
 
  
 

	
 
  os  << index << "[ {" << x << ", " << y << ", " << z << "}: {";
 
  
 

	
 
  os << "Neighbors = { ";
 

	
 
  for (list<Neighbor>::const_iterator i =  owners.begin(); i!=owners.end(); i++) {
 
    os << " {" << i->cell->Index() << " " << i->nb1->Index() << " " << i->nb2->Index() << "} ";
 
  }
 
  os << " } " << endl;
 

	
 
  return os;
 

	
 
}
 

	
 

	
 
#ifdef QTGRAPHICS
 
void Node::DrawIndex(QGraphicsScene *c) const {
 

	
 
  //return DrawOwners(c);
 
  stringstream text;
 
  text << index;
 
  QGraphicsSimpleTextItem *number = new QGraphicsSimpleTextItem ( QString (text.str().c_str()), 0, c );
 
  number->setFont( QFont( "Helvetica", par.nodenumsize, QFont::Bold) );
 
  number->setPen( QPen (par.textcolor) );
 
  number->setZValue(20);
 
  number->show();
 
  Vector offs=Cell::Offset();
 
  number -> setPos(
 
		   ((offs.x+x)*Cell::Factor()),
 
		   ((offs.y+y)*Cell::Factor()) );
 
}
 

	
 
void Node::DrawOwners(QGraphicsScene *c) const {
 
  
 

	
 
  stringstream text;
 
  
 
  
 
  text << owners.size();
 

	
 
  text << owners.size();
 
  
 
  
 
  QGraphicsSimpleTextItem *number = new QGraphicsSimpleTextItem ( QString (text.str().c_str()), 0, c );
 
  number->setFont( QFont( "Helvetica", par.nodenumsize, QFont::Bold) );
 
  number->setPen( QPen(par.textcolor) );
 
  number->setZValue(20);
 
  number->show();
 
  Vector offs=Cell::Offset();
 
  
 

	
 
  number ->setPos(((offs.x+x)*Cell::Factor()),
 
		  ((offs.y+y)*Cell::Factor()) );
 
}
 

	
 

	
 
QVector<qreal> Node::NeighbourAngles(void)
 
{
 
  QVector<qreal> angles;
 
  for (list<Neighbor>::iterator i=owners.begin();
 
       i!=owners.end();
 
       i++) {
 

	
 
QVector<qreal> Node::NeighbourAngles(void) {
 
	
 
	QVector<qreal> angles;
 
	for (list<Neighbor>::iterator i=owners.begin();
 
		 i!=owners.end();
 
		 i++) {
 
		
 
		Vector v1 = (*this - *i->nb1).Normalised();
 
		Vector v2 = (*this - *i->nb2).Normalised();	
 
	
 
		double angle = v1.SignedAngle(v2);
 
		if (angle<0) {
 
			//cerr << "Changing sign of angle " << angle << endl;
 
			angle = angle + 2*Pi;
 
		}
 
		angles.push_back(angle);
 
		
 
		//cerr << "Cell " << i->cell->Index() << ": " <<  v1 << " and " << v2 << ": angle = " << angles.back() << ", " << v1.Angle(v2) << endl;
 
		
 
	}
 
	
 
	double sum=0.;
 
	for (QVector<qreal>::iterator i=angles.begin();
 
		 i!=angles.end();
 
		 i++) {
 
		sum+=*i;
 
	}
 
	//cerr << "Angle sum = " << sum << endl;
 
	// Check if the summed angle is different from 2 Pi 
 
	if (fabs(sum-(2*Pi))>0.0001) {
 
		
 
		MyWarning::warning("sum = %f",sum);
 
	}
 
		return angles;
 
    Vector v1 = (*this - *i->nb1).Normalised();
 
    Vector v2 = (*this - *i->nb2).Normalised();	
 

	
 
    double angle = v1.SignedAngle(v2);
 
    if (angle<0) {
 
      //cerr << "Changing sign of angle " << angle << endl;
 
      angle = angle + 2*Pi;
 
    }
 
    angles.push_back(angle);
 

	
 
    //cerr << "Cell " << i->cell->Index() << ": " <<  v1 << " and " << v2 
 
    //     << ": angle = " << angles.back() << ", " << v1.Angle(v2) << endl;
 

	
 
  }
 

	
 
  double sum=0.;
 
  for (QVector<qreal>::iterator i=angles.begin();
 
       i!=angles.end();
 
       i++) {
 
    sum+=*i;
 
  }
 
  //cerr << "Angle sum = " << sum << endl;
 
  // Check if the summed angle is different from 2 Pi 
 
  if (fabs(sum-(2*Pi))>0.0001) {
 

	
 
    MyWarning::warning("sum = %f",sum);
 
  }
 
  return angles;
 
}
 

	
 

	
 

	
 
#endif
 

	
 

	
 
ostream &operator<<(ostream &os, const Node &n) {
 
  n.print(os);
 
  return os;
 
}
 

	
 
/* finis */
src/node.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _NODE_H_
 
#define _NODE_H_
 

	
 
#include <list>
 
//#include <pair>
 

	
 
#include <libxml/parser.h>
 
#include <libxml/tree.h>
 

	
 
#ifdef QTGRAPHICS
 
#include <QGraphicsScene>
 
#include <qcolor.h>
 
#include <iostream>
 
#endif
 
#include "vector.h"
 
#include "random.h"
 
#include "parameter.h"
 
#include "cell.h"
 
#include "modelelement.h"
 

	
 
#include <QVector>
 

	
 
#include "Neighbor.h"
 

	
 
extern Parameter par;
 

	
 
class Edge {
 
  
 
public:
 

	
 
 public:
 

	
 
  Edge(void) {
 
    first=0;
 
    second=0;
 
  }
 

	
 
  Edge(Node *f, Node *s) {
 
    first=f;
 
    second=s;
 
  }
 
  
 

	
 
  // Copy Constructor
 
  Edge(const Edge &src) {
 
    first=src.first;
 
    second=src.second;
 
  }
 

	
 
  // Ambidextrous equivalence 
 
  inline bool operator==(const Edge &e) {
 
    return ( (first==e.first && second==e.second) ||
 
	     (first==e.second && second==e.first) );
 
  }
 
  
 

	
 

	
 
  // Output the Edge
 
  ostream &print(ostream &os) const;
 
    
 
  
 

	
 
  Node *first, *second;
 
};
 

	
 

	
 
class NodeSet;
 

	
 
// this class is a node in a cell wall
 
class Node : public Vector {
 

	
 
  friend class Mesh;
 
  friend class CellBase;
 
  friend class Cell;
 
  friend class WallBase;
 
  friend class Wall;
 
  friend class NodeSet;
 
  friend class FigureEditor;
 

	
 
public:
 
 public:
 
  Node(void);
 

	
 
  Node(int index); // if want to construct a node, and not increase nnodes
 

	
 
  Node(double x,double y, double z=0);
 

	
 
  Node(const Node &src);
 

	
 
  explicit Node(const Vector &src); // "nonconverting" - explicit constructor syntax required
 

	
 
  virtual ~Node() {}
 

	
 
  inline int Index(void) const { return index; }
 

	
 
  inline bool IndexEquals(int i) { return i == index; }
 

	
 
  inline bool BoundaryP(void) const { return boundary; }
 

	
 
  inline void SetBoundary(void) { boundary = true; }
 

	
 
  inline void UnsetBoundary(void) { boundary = false; }
 

	
 
  inline void SetSAM(void) { sam = true; }
 

	
 
  inline void toggleBoundary(void) {
 
    boundary = !boundary;
 
  }
 
  
 

	
 

	
 
  Cell &getCell(const Neighbor &i);
 
  
 

	
 
  ostream &print(ostream &os) const;
 
  void XMLAdd(xmlNodePtr nodes_node) const;
 
  
 

	
 
#ifdef QTGRAPHICS
 
  void Draw(QGraphicsScene &c, QColor color=QColor("black"), int size = 10) const;
 
  void DrawIndex(QGraphicsScene *c) const;
 
  void DrawOwners(QGraphicsScene *c) const;
 
#endif
 
  
 

	
 
  // temporary function for easier debugging
 
  inline int CellsSize(void) const {
 
    return owners.size();
 
  }
 
  inline int CellsSize(void) const { return owners.size(); }
 

	
 
  inline int Value(void) const { return owners.size(); }
 

	
 
  inline int Value(void) const {
 
    return owners.size();
 
  }
 
  void Fix(void) { fixed=true; }
 

	
 
  inline bool Fixed(void) const { return fixed; }
 

	
 
  void Fix(void) {
 
    fixed=true;
 
  }
 
  inline bool Fixed(void) const {
 
    return fixed;
 
  }
 
  inline void Unfix(void) {
 
    fixed=false;
 
  }
 
  inline void MarkDead(void) {
 
    dead=true;
 
  }
 
  inline bool DeadP(void) {
 
    return dead;
 
  }
 
  inline void Unfix(void) { fixed=false; }
 

	
 
  inline void MarkDead(void) { dead=true; }
 

	
 
  inline bool DeadP(void) { return dead; }
 

	
 
  inline void Mark(void) {
 
    marked=true;
 
  }
 
  inline void Unmark(void) {
 
    marked=false;
 
  }
 
  inline bool Marked(void) const {
 
    return marked;
 
  }
 
  
 
  inline void Mark(void) { marked=true; }
 

	
 
  inline void Unmark(void) { marked=false; }
 

	
 
  inline bool Marked(void) const { return marked; }
 

	
 
  inline void setPos( Vector p ) { 
 
    x = p.x;
 
    y = p.y;
 
    z = p.z;
 
  }
 

	
 
  inline bool SamP(void) const { return sam; }
 

	
 
  //!\brief Calculate angles with neighboring vertices
 
  //! Sum of angles should be 2*Pi
 
  QVector<qreal> NeighbourAngles(void);
 
private:
 
  
 
 private:
 

	
 
  // "owners" lists the cells to which this cell belong
 
  // and the two neighboring nodes relative to each cell
 
  list< Neighbor > owners;
 
  
 

	
 
  Mesh *m;
 
  int index;
 
  static int nnodes;
 
  static double target_length;
 
  
 

	
 
  // if the node belongs to a NodeSet, node_set contains the pointer. Otherwise it is 0.
 
  NodeSet *node_set; 
 
  // fixed nodes cannot move. E.g. to represent the petiole
 
  bool fixed;
 
  bool boundary; // true if node is at the edge of the leaf
 
  bool sam; // true if node is connected to the shoot
 
  bool dead;
 
  bool marked;
 
};
 

	
 
ostream &operator<<(ostream &os, const Node &n);
 

	
 
inline ostream &operator<<(ostream &os, const Edge &e) {
 
  e.print(os);
 
  return os;
 
}
 

	
 
#endif
 

	
 
#endif
 
/* finis */
src/nodeitem.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include <QGraphicsScene>
 
#include <QGraphicsItem>
 
#include <QPainter>
 
#include <QStyleOption>
 
#include <Qt>
 
#include "nodeitem.h"
 
#include "parameter.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
extern Parameter par;
 

	
 
NodeItem::NodeItem( Node *n, QGraphicsScene *canvas )
 
  : QGraphicsItem( 0, canvas ), SimItemBase( n, canvas) {
 
  
 

	
 
  brush = Qt::darkGray;
 
  
 

	
 
  const double mag = par.node_mag;
 
  ellipsesize=QRectF(-1*mag, -1*mag, 2*mag, 2*mag);
 

	
 
}
 

	
 
void NodeItem::userMove(double dx, double dy) {
 
void NodeItem::userMove(double dx, double dy)
 
{
 
  QGraphicsItem::moveBy( dx, dy );
 
  
 

	
 
  class_cast<Node *>(obj)->x += (dx/Cell::Magnification());
 
  class_cast<Node *>(obj)->y += (dy/Cell::Magnification());
 
}
 

	
 

	
 

	
 
void NodeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
 
{
 
  option = NULL; // use assignment merely to obviate compilation warning
 

	
 
  option = NULL; // use assignment merely to obviate compilation warning
 
  
 
  painter->setBrush(brush);
 
  painter->setPen(Qt::NoPen);
 
  painter->drawEllipse(ellipsesize);
 
}
 

	
 

	
 
QPainterPath NodeItem::shape() const
 
{
 
    QPainterPath path;
 
    path.addEllipse(ellipsesize);
 
    return path;
 
  QPainterPath path;
 
  path.addEllipse(ellipsesize);
 
  return path;
 
}
 

	
 
QRectF NodeItem::boundingRect() const
 
{
 
  qreal penwidth = 0;// painter->pen()->widthF();
 
  return QRectF(ellipsesize.x()-penwidth/2.,ellipsesize.y()-penwidth/2.,
 
		ellipsesize.width()+penwidth, ellipsesize.height()+penwidth);
 
}
 

	
 
// polymorphic OnClick functions
 
void NodeItem::OnClick(void) {
 
void NodeItem::OnClick(void)
 
{
 
  Node *n = &getNode();
 
  n->toggleBoundary();
 
  setColor();
 
  update();
 
}
 

	
 
void NodeItem::OnClick(const Qt::MouseButton &mb) {
 
void NodeItem::OnClick(const Qt::MouseButton &mb)
 
{
 
  if (mb == Qt::LeftButton) {
 
    Node *n = &getNode();
 
    n->toggleBoundary();
 
    setColor();
 
    update();
 

	
 
  }
 
}
 

	
 
void NodeItem::setColor(void) {
 

	
 
void NodeItem::setColor(void)
 
{
 
  static QColor indian_red("IndianRed");
 
  static QColor deep_sky_blue("DeepSkyBlue");
 
  static QColor purple("Purple");
 
  
 

	
 
  Node &n=getNode();
 

	
 
  if (n.SamP()) {
 
    setBrush( purple );
 
  } else {
 
    if (n.BoundaryP()) {
 
      setBrush( deep_sky_blue );
 
    } 
 
    else {
 
      setBrush( indian_red );
 
    }
 
  }
 
}
 

	
 
/* finis */
src/nodeitem.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _NODEITEM_H_
 
#define _NODEITEM_H_
 

	
 
#include <QGraphicsScene>
 
#include <QGraphicsItem>
 
#include "simitembase.h"
 
#include "node.h"
 
#include "cell.h"
 

	
 
class NodeItem: public QGraphicsItem, public SimItemBase
 
{
 
public:
 
 public:
 
  NodeItem( Node *n, QGraphicsScene *canvas );
 
  ~NodeItem() {}
 
  Node &getNode(void) const { return *class_cast<Node*>(obj); }
 
  virtual void userMove(double dx, double dy);  
 
  
 

	
 
  QRectF boundingRect() const;
 
  void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
 
  QPainterPath shape() const;
 
  void setBrush( QBrush newbrush) { brush = newbrush; }
 
  void setColor(void); 
 
  /*! We use this function internally, to (somewhat) interactively edit init configurations.
 
    Simply put the property to be change upon clicking a node in this function. */
 
  void OnClick( const Qt::MouseButton &mb );
 
  void OnClick(void);
 
protected:
 
 protected:
 
  QBrush brush;
 
  QRectF ellipsesize;
 

	
 
private:
 
 private:
 
};
 

	
 
#endif
 

	
 
/* finis */
src/nodeset.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include <ostream>
 
#include "nodeset.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
ostream &operator<<(ostream &os, const NodeSet &ns)  {
 
  ns.print(os);
 
  return os;
 
}
 

	
 
/* finis */
src/nodeset.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _NODESET_H_
 
#define _NODESET_H_
 

	
 
#include <algorithm>
 
#include <numeric>
 
#include <list>
 
#include <iterator>
 
#include "node.h"
 

	
 
class NodeSet : public list<Node *> {
 
  
 

	
 
 public:
 
  NodeSet(void) {
 
    done = false;
 
  }
 
  
 

	
 
  inline bool DoneP(void) { return done; }
 
  inline void ResetDone(void) { done = false; }
 
  
 

	
 
  void AddNode(Node * n) {
 
    push_back(n);
 
    n->node_set = this;
 
  }
 

	
 
  list <Cell *> getCells(void) {
 
    
 

	
 
    list<Cell *> cellset;
 
    
 

	
 
    for (list<Node *>::const_iterator i=begin();
 
	 i!=end();
 
	 i++) {
 
      transform ( (*i)->owners.begin(), (*i)->owners.end(), back_inserter( cellset ) , mem_fun_ref ( &Neighbor::getCell ));
 
    }
 
    
 

	
 
    cellset.sort();
 
    
 

	
 
    // remove all non-unique elements
 
    // (unique moves all unique elements to the front and returns an iterator to the end of the unique elements;
 
    // so we simply erase all remaining elements.
 
    cellset.erase(::unique(cellset.begin(), cellset.end() ), 
 
		  cellset.end() );
 
    
 
    cellset.erase(::unique(cellset.begin(), cellset.end() ), cellset.end() );
 

	
 
    // remove boundary_polygon
 
    cellset.erase( find_if ( cellset.begin(), cellset.end(), mem_fun( &Cell::BoundaryPolP  ) ) );
 
    return cellset;
 
  }
 

	
 
  void CleanUp(void) {
 
    
 

	
 
    // remove double Nodes from the set
 
    sort();
 
    erase(::unique(begin(), end() ), 
 
	      end() );
 
    
 
    
 
	  end() );
 

	
 

	
 
  }
 
  void print(ostream &os) const {
 
    transform( begin(), end(), ostream_iterator<int>( os, " " ), mem_fun( &Node::Index ) );
 
  }
 
  
 

	
 
  /*! Attempt a move over (rx, ry)
 
    reject if energetically unfavourable.
 
  */
 

	
 
  void AttemptMove(double rx, double ry) {
 
    
 

	
 
    done = true;
 
    // 1. Collect list of all attached to the nodes in the set
 
    list<Cell *> celllist = getCells();
 
    
 

	
 
    // 2. Sum the current energy of these cells
 
    double old_energy=0.;
 
    double sum_stiff = 0.;
 
    for ( list<Cell *>::const_iterator i = celllist.begin(); 
 
	  i!=celllist.end();
 
	  ++i ) {
 

	
 
      old_energy += (*i)->Energy();
 
      sum_stiff += (*i)->Stiffness();
 
    }
 
    
 

	
 
    // 3. (Temporarily) move the set's nodes.
 
    for ( list<Node *>::iterator n = begin();
 
	  n!=end();
 
	  ++n ) {
 
       
 

	
 
      (*n)->x+=rx;
 
      (*n)->y+=ry;
 
      // (*n)->z += rz;
 
       
 
    }
 
    
 

	
 
    // 4. Recalculate the energy
 
    double new_energy = 0.;
 
    for ( list<Cell *>::const_iterator i = celllist.begin(); 
 
	  i!=celllist.end();
 
	  ++i ) {
 
      
 

	
 
      new_energy += (*i)->Energy();
 
    }
 
    
 
    
 

	
 

	
 
    // 5. Accept or Reject DeltaH
 
	  double dh = new_energy - old_energy;
 
	  
 
	  list<int> new_areas;
 
	  
 
	 // cerr << "Nodeset says: dh = " << dh << " ...";
 
	  if (dh < -sum_stiff || RANDOM()<exp((-dh - sum_stiff)/par.T) ) {
 
		
 
		// ACCEPT
 
		// recalculate areas of cells
 
		for_each ( celllist.begin(), celllist.end(), mem_fun ( &Cell::RecalcArea ) );
 
		
 
		// recalculate integrals of cells
 
		for_each ( celllist.begin(), celllist.end(), mem_fun ( &Cell::SetIntegrals ) );
 
      
 
		
 
    double dh = new_energy - old_energy;
 

	
 
    list<int> new_areas;
 

	
 
    // cerr << "Nodeset says: dh = " << dh << " ...";
 
    if (dh < -sum_stiff || RANDOM()<exp((-dh - sum_stiff)/par.T) ) {
 

	
 
      // ACCEPT
 
      // recalculate areas of cells
 
      for_each ( celllist.begin(), celllist.end(), mem_fun ( &Cell::RecalcArea ) );
 

	
 
      // recalculate integrals of cells
 
      for_each ( celllist.begin(), celllist.end(), mem_fun ( &Cell::SetIntegrals ) );
 

	
 

	
 
    } else {
 
      // REJECT
 
      
 

	
 
      // Move the set's nodes back to their original position
 
      for ( list<Node *>::iterator n = begin();
 
	    n!= end();
 
	    ++n ) {
 
	
 

	
 
	(*n)->x-=rx;
 
	(*n)->y-=ry;
 
	  }
 
      
 
      
 
      }
 
    }
 
  }
 
  
 

	
 
  void XMLAdd(xmlNode *root) const;
 
  void XMLRead(xmlNode *root, Mesh *m);
 
 private:
 
  bool done;
 
};
 

	
 
ostream &operator<<(ostream &os, const NodeSet &ns);
 
#endif
 

	
 
/* finis */
src/output.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 
 
#include <string>
 
#include <stdio.h>
 
#include <string.h>
 
#include <stdlib.h>
 
#include <errno.h>
 
#include <sys/types.h>
 
#include <sys/stat.h>
 
#include "warning.h"
 
#include "parameter.h"
 
#include "output.h"
 
 
 
#include <QDir>
 
#include <QFileInfo>
 
 
static const std::string _module_id("$Id$");
 
 
using namespace MyWarning;
 
 
#define FNAMESIZE 100
 
 
int OpenFileAndCheckExistance(FILE **fp,const char *fname,char *ftype) {
 
  
 
 
  *fp=fopen(fname,ftype);
 
  if (*fp==NULL) 
 
    return FALSE;
 
  
 
 
  if (!strncmp(ftype,"a",1)) {
 
    if (ftell(*fp)>0L) return TRUE;
 
    else return FALSE;
 
  } else return TRUE;
 
}
 
 
int FileExistsP(const char *fname) {
 
  
 
 
  FILE *fp;
 
  fp=fopen(fname,"r");
 
  if (fp==NULL)
 
    return FALSE;
 
  
 
 
  fclose(fp);
 
  return TRUE;
 
}
 
 
}
 
		       
 
int YesNoP(const char *message) {
 
  
 
 
  char answer[100];
 
 
  fprintf(stderr,"%s (y/n) ",message);
 
  fflush(stderr);
 
  
 
 
  scanf("%s",answer);
 
  while (strcmp(answer,"y") && strcmp(answer,"n")) {
 
    fprintf(stderr,"\n\bPlease answer 'y' or 'n'. ");
 
    fflush(stderr);
 
    scanf("%s",answer);
 
  }
 
  
 
 
  if (!strcmp(answer,"y")) return TRUE;
 
  
 
 
  return FALSE;
 
    
 
}
 
 
 
FILE *OpenWriteFile(const char *filename) 
 
{
 
 
  char fname[FNAMESIZE];
 
 
  FILE *fp;
 
 
  fprintf(stderr,"Opening %s for writing\n",filename);
 
	
 
 
  if(FileExistsP(filename)==TRUE) {
 
  
 
 
    if (false/*par.interactive*/) {
 
      char *message=(char *)malloc(2000*sizeof(char));
 
      if (!YesNoP("File exists, overwrite?")) {
 
	sprintf(message," Could not open file %s for writing, exiting... \n"
 
		,filename);
 
	//exit(0);
 
	throw(message);
 
      }
 
    } else {
 
      /* Rename old file */
 
      sprintf(fname, "%s~",filename);
 
      rename(filename, fname);
 
      
 
    }
 
  }
 
  
 
 
  strncpy(fname, filename, FNAMESIZE-1);
 
  
 
 
  if ((fp=fopen(fname,"w"))==NULL) {
 
    char *message=(char *)malloc(2000*sizeof(char));
 
    sprintf(message," Could not open file %s for writing: "
 
	    ,fname);
 
    perror("");
 
    throw(message);
 
  }
 
	
 
  return fp;
 
}
 
 
 
FILE *OpenReadFile(const char *filename) 
 
{
 
  FILE *fp;
 
 
  fprintf(stderr,"Opening %s for reading\n",filename);
 
  
 
 
  if((OpenFileAndCheckExistance(&fp,filename,"r"))==FALSE) {	
 
    char *message=(char *)malloc(2000*sizeof(char));
 
    sprintf(message," File %s not found or empty, exiting... \n" ,filename);
 
    throw(message);
 
  }
 
  return fp;
 
}
 
 
 
char *ReadLine(FILE *fp) 
 
{
 
  /* does almost the same as fgetln(), but DEC Unix doesn't understand
 
	 fgetln(). Also I want my function to return a real C string,
 
	 terminated by a \0. */
 
     fgetln(). Also I want my function to return a real C string,
 
     terminated by a \0. */
 
 
  /* The function reads a line from file *fp, and returns a pointer to the
 
	 line read, which can be freed with a normal free(). The length of the
 
	 string is written in *len */
 
  
 
     line read, which can be freed with a normal free(). The length of the
 
     string is written in *len */
 
 
#define INITIAL_BUFSIZE 100
 
  
 
 
  char *tmpstring;
 
  int character;
 
  long bufsize;
 
  char *line;
 
  int pos;
 
 
  CheckFile(fp);
 
    
 
 
  /* first allocate a string with a standard length */
 
  bufsize=INITIAL_BUFSIZE;
 
  MEMORYCHECK(tmpstring=(char *)malloc(bufsize*sizeof(char)));
 
 
  pos=0;
 
  
 
 
  while ((character=getc(fp))!=EOF && /* read a character and check */
 
		 character!='\n') {
 
 
	
 
	tmpstring[pos]=(char)character;
 
	(pos)++;
 
	 character!='\n') {
 
 
	if (pos >= bufsize) {
 
	  /* line is longer than initial_bufsize, reallocate space */
 
	  bufsize+=INITIAL_BUFSIZE;
 
	  MEMORYCHECK(tmpstring=(char *)realloc(tmpstring,bufsize*sizeof(char)));
 
	  
 
	}
 
		   
 
    tmpstring[pos]=(char)character;
 
    (pos)++;
 
 
    if (pos >= bufsize) {
 
      /* line is longer than initial_bufsize, reallocate space */
 
      bufsize+=INITIAL_BUFSIZE;
 
      MEMORYCHECK(tmpstring=(char *)realloc(tmpstring,bufsize*sizeof(char)));
 
    }
 
  }
 
 
 
  if (character==EOF) {
 
	
 
	if (pos==0) {
 
	  /* EOF was reached, while no characters were read */
 
	  free(tmpstring);
 
	  return NULL;
 
 
	}
 
	if (ferror(fp)) {
 
	  error("I/O error in ReadLine(%ld): %s\n",fp, strerror(errno));
 
	}
 
	
 
    if (pos==0) {
 
      /* EOF was reached, while no characters were read */
 
      free(tmpstring);
 
      return NULL;
 
    }
 
    if (ferror(fp)) {
 
      error("I/O error in ReadLine(%ld): %s\n",fp, strerror(errno));
 
    }
 
  }
 
 
  }
 
  
 
  /* Allocate enough memory for the line */
 
  MEMORYCHECK(line=(char *)malloc((++(pos))*sizeof(char)));
 
 
  strncpy(line,tmpstring,(pos)-1);
 
  free(tmpstring);
 
  
 
 
  line[pos-1]='\0';
 
  return line;
 
    
 
}
 
 
 
void CheckFile(FILE *fp) 
 
{
 
  if (ftell(fp)<0) {
 
	/* file is probably not open, or another error occured */
 
	error("File error (fp=%ld): %d %s\n",fp,errno,strerror(errno));
 
    /* file is probably not open, or another error occured */
 
    error("File error (fp=%ld): %d %s\n",fp,errno,strerror(errno));
 
  }
 
  /* File pointer is ok */
 
}
 
 
char *Chext(char *filename) {
 
 
  /* Chop the extension from a filename */
 
  
 
 
  /* Search backwards until a dot */
 
  
 
 
  /* Remember to free the memory allocated by this function */
 
  /* ( free(result) ) */
 
  
 
 
  /* not yet tested */
 
 
  int i;
 
  char *result;
 
 
  for (i=strlen(filename)-1;i>=0;i--) {
 
    if (filename[i]=='.') 
 
      break;
 
    
 
  }
 
  
 
 
  /* No . found */
 
  if (i==0) {
 
    
 
 
    result=strdup(filename);
 
  } else {
 
   
 
 
    /* . found */
 
    result=(char *)malloc((i+1)*sizeof(char));
 
    strncpy(result, filename, i);
 
  }
 
  return result;
 
  
 
  
 
}
 
 
void MakeDir(const char *dirname) {
 
 
#ifdef QTGRAPHICS
 
  QFileInfo file_info(dirname);
 
  
 
 
  //check for existance
 
  if (file_info.exists()) {
 
    
 
 
    if (file_info.isDir()) {
 
      // OK 
 
      cerr << "Using existing directory " << dirname << " for data storage." << endl;
 
      return;
 
    } else {
 
      char *message = new char[MESS_BUF_SIZE+1];
 
      snprintf(message, MESS_BUF_SIZE, "%s is not a directory", dirname);
 
      cerr << message << endl;
 
      throw(message);
 
    }
 
    
 
  }
 
 
  // make directory
 
  QDir dir;
 
  if (!dir.mkdir(QString(dirname))) {
 
    char *message = new char[MESS_BUF_SIZE+1];
 
    snprintf(message,MESS_BUF_SIZE,"%s: Error in making directory %s",strerror(errno),dirname);
 
    warning(message);
 
    //strerror(message);
 
    //exit(1);
 
    return;
 
  }
 
  
 
 
  // check
 
  
 
 
 
#else
 
  
 
 
  int status;
 
  char message[MESS_BUF_SIZE];
 
  
 
 
  status=mkdir(dirname, S_IRWXU); // S_IRWXU: Read, Write, Execute by Owner 
 
  
 
 
  if (status<0) { // error occurred
 
    
 
 
    //check for existance
 
    
 
 
    if (errno==EEXIST) {
 
      
 
 
      // Check whether it is a directory 
 
      struct stat buf;
 
      stat(dirname, &buf);
 
      if (S_ISDIR(buf.st_mode)) {
 
	// OK 
 
	extern  Parameter par;
 
	if (false /* && par.interactive*/) {
 
	  fprintf(stderr,"Using existing directory %s for data storage.\n",dirname);
 
	  if (!YesNoP("OK?")) {
 
	    // User doesn't agree. Exit
 
	    exit(1);
 
	  }
 
	} else {
 
	  fprintf(stderr,"Using existing directory %s for data storage.\n",dirname);
 
	}
 
      } else {
 
	snprintf(message, MESS_BUF_SIZE, "%s is not a directory", dirname);
 
	perror(message);
 
	exit(1);
 
      }
 
    } else {
 
      // a different error occurred. Print error and quit 
 
      
 
 
      snprintf(message,MESS_BUF_SIZE,"Error in making directory %s",dirname);
 
      perror(message);
 
      exit(1);
 
      
 
    }
 
  
 
 
 
  }
 
 
#endif
 
}
 
 
 
/* finis */
src/output.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _OUTPUT_H_
 
#define _OUTPUT_H_
 

	
 
#ifdef __cplusplus
 
extern "C" {
 
#endif
 

	
 
int OpenFileAndCheckExistance(FILE **fp,const char *fname,char *ftype);
 
int YesNoP(const char *message);
 
FILE *OpenWriteFile(const char *filename);
 
FILE *OpenGZippedWriteFile(const char *filename);
 
FILE *OpenReadFile(const char *filename);
 
char *ReadLine(FILE *fp);
 
void CheckFile(FILE *fp);
 
int FileExistsP(const char *fname);
 
char *Chext(char *filename);
 
void MakeDir(const char *dirname);
 
bool CanWeWriteP(char *filename);
 
  int OpenFileAndCheckExistance(FILE **fp,const char *fname,char *ftype);
 
  int YesNoP(const char *message);
 
  FILE *OpenWriteFile(const char *filename);
 
  FILE *OpenGZippedWriteFile(const char *filename);
 
  FILE *OpenReadFile(const char *filename);
 
  char *ReadLine(FILE *fp);
 
  void CheckFile(FILE *fp);
 
  int FileExistsP(const char *fname);
 
  char *Chext(char *filename);
 
  void MakeDir(const char *dirname);
 
  bool CanWeWriteP(char *filename);
 

	
 
#ifdef __cplusplus
 
}
 
#endif
 

	
 

	
 
#define MESS_BUF_SIZE 160
 
#ifndef FALSE
 
#define FALSE 0
 
#define TRUE 1
 
#endif
 

	
 
#endif
 

	
 
/* finis */
src/parameter.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include "parameter.h"
 
#include <cstdio>
 
#include <cstring>
 
#include <cstdlib>
 
#include <cerrno>
 
#include <iostream>
 
#include <sstream>
 
#include "output.h"
 
#include "parse.h"
 
#include "xmlwrite.h"
 
#include "warning.h"
 
#include <QLocale>
 

	
 
using namespace std;
 

	
 
static const std::string _module_id("$Id$");
 

	
 
Parameter::Parameter() {
 
  arrowcolor = strdup("white");
 
  arrowsize = 100;
 
  textcolor = strdup("red");
 
  cellnumsize = 1;
 
  nodenumsize = 1;
 
  node_mag = 1.0;
 
  outlinewidth = 1.0;
 
  cell_outline_color = strdup("forestgreen");
 
  resize_stride = 10;
 
  T = 1.0;
 
  lambda_length = 100.;
 
  lambda_celllength = 0.;
 
  target_length = 60.;
 
  cell_expansion_rate = 1.;
 
  cell_div_expansion_rate = 0.;
 
  auxin_dependent_growth = true;
 
  ode_accuracy = 1e-4;
 
  mc_stepsize = 0.4;
 
  mc_cell_stepsize = 0.2;
 
  energy_threshold = 1000.;
 
  bend_lambda = 0.;
 
  alignment_lambda = 0.;
 
  rel_cell_div_threshold = 2.;
 
  rel_perimeter_stiffness = 2;
 
  collapse_node_threshold = 0.05;
 
  morphogen_div_threshold = 0.2;
 
  morphogen_expansion_threshold = 0.01;
 
  copy_wall = true;
 
  source = 0.;
 
  D = new double[15];
 
  D[0] = 0.;
 
  D[1] = 0.0;
 
  D[2] = 0.0;
 
  D[3] = 0.;
 
  D[4] = 0.;
 
  D[5] = 0.;
 
  D[6] = 0.;
 
  D[7] = 0.;
 
  D[8] = 0.;
 
  D[9] = 0.;
 
  D[10] = 0.;
 
  D[11] = 0.;
 
  D[12] = 0.;
 
  D[13] = 0.;
 
  D[14] = 0.;
 
  initval = new double[15];
 
  initval[0] = 0.;
 
  initval[1] = 0.;
 
  initval[2] = 0.;
 
  initval[3] = 0.;
 
  initval[4] = 0.;
 
  initval[5] = 0.;
 
  initval[6] = 0.;
 
  initval[7] = 0.;
 
  initval[8] = 0.;
 
  initval[9] = 0.;
 
  initval[10] = 0.;
 
  initval[11] = 0.;
 
  initval[12] = 0.;
 
  initval[13] = 0.;
 
  initval[14] = 0.;
 
  k1 = 1.;
 
  k2 = 0.3;
 
  r = 1.;
 
  kr = 1.;
 
  km = 1.;
 
  Pi_tot = 1.;
 
  transport = 0.036;
 
  ka = 1;
 
  pin_prod = 0.001;
 
  pin_prod_in_epidermis = 0.1;
 
  pin_breakdown = 0.001;
 
  pin_breakdown_internal = 0.001;
 
  aux1prod = 0.001;
 
  aux1prodmeso = 0.;
 
  aux1decay = 0.001;
 
  aux1decaymeso = 0.1;
 
  aux1transport = 0.036;
 
  aux_cons = 0.;
 
  aux_breakdown = 0.;
 
  kaux1 = 1;
 
  kap = 1;
 
  leaf_tip_source = 0.001;
 
  sam_efflux = 0.0001;
 
  sam_auxin = 10.;
 
  sam_auxin_breakdown = 0;
 
  van3prod = 0.002;
 
  van3autokat = 0.1;
 
  van3sat = 10;
 
  k2van3 = 0.3;
 
  dt = 0.1;
 
  rd_dt = 1.0;
 
  datadir = strdup(".");
 
  movie = false;
 
  nit = 100000;
 
  maxt = 1000.;
 
  storage_stride = 10;
 
  xml_storage_stride = 500;
 
  rseed = -1;
 
  constituous_expansion_limit = 16;
 
  vessel_inh_level = 1;
 
  vessel_expansion_rate = 0.25;
 
  d = 0.;
 
  e = 0.;
 
  f = 0.;
 
  c = 0.;
 
  mu = 0.;
 
  nu = 0.;
 
  rho0 = 0.;
 
  rho1 = 0.;
 
  c0 = 0.;
 
  gamma = 0.;
 
  eps = 0.;
 
  k = new double[15];
 
  k[0] = 0.;
 
  k[1] = 0.0;
 
  k[2] = 0.0;
 
  k[3] = 0.;
 
  k[4] = 0.;
 
  k[5] = 0.;
 
  k[6] = 0.;
 
  k[7] = 0.;
 
  k[8] = 0.;
 
  k[9] = 0.;
 
  k[10] = 0.;
 
  k[11] = 0.;
 
  k[12] = 0.;
 
  k[13] = 0.;
 
  k[14] = 0.;
 
  i1 = 0;
 
  i2 = 0;
 
  i3 = 0;
 
  i4 = 0;
 
  i5 = 0;
 
  s1 = strdup("");
 
  s2 = strdup("");
 
  s3 = strdup("");
 
  b1 = false;
 
  b2 = false;
 
  b3 = false;
 
  b4 = false;
 
  dir1 = strdup(".");
 
  dir2 = strdup(".");
 
}
 

	
 
Parameter::~Parameter() {
 
  
 

	
 
  // destruct parameter object
 

	
 
  // free string parameter
 

	
 
  CleanUp();
 

	
 
}
 

	
 
void Parameter::CleanUp(void) {
 
  if (arrowcolor) 
 
     free(arrowcolor);
 
    free(arrowcolor);
 
  if (textcolor) 
 
     free(textcolor);
 
    free(textcolor);
 
  if (cell_outline_color) 
 
     free(cell_outline_color);
 
    free(cell_outline_color);
 
  if (D) 
 
     free(D);
 
    free(D);
 
  if (initval) 
 
     free(initval);
 
    free(initval);
 
  if (datadir) 
 
     free(datadir);
 
    free(datadir);
 
  if (k) 
 
     free(k);
 
    free(k);
 
  if (s1) 
 
     free(s1);
 
    free(s1);
 
  if (s2) 
 
     free(s2);
 
    free(s2);
 
  if (s3) 
 
     free(s3);
 
    free(s3);
 
  if (dir1) 
 
     free(dir1);
 
    free(dir1);
 
  if (dir2) 
 
     free(dir2);
 

	
 
    free(dir2);
 
}
 

	
 
void Parameter::Read(const char *filename) {
 
  
 

	
 
  static bool ReadP=false;
 

	
 
  if (ReadP) {
 

	
 
    //throw "Run Time Error in parameter.cpp: Please Read parameter file only once!!";
 
    CleanUp();
 
    
 

	
 
  } else
 
    ReadP=true;
 

	
 
  FILE *fp=OpenReadFile(filename);
 

	
 

	
 
  arrowcolor = sgetpar(fp, "arrowcolor", "white", true);
 
  arrowsize = fgetpar(fp, "arrowsize", 100, true);
 
  textcolor = sgetpar(fp, "textcolor", "red", true);
 
  cellnumsize = igetpar(fp, "cellnumsize", 1, true);
 
  nodenumsize = igetpar(fp, "nodenumsize", 1, true);
 
  node_mag = fgetpar(fp, "node_mag", 1.0, true);
 
  outlinewidth = fgetpar(fp, "outlinewidth", 1.0, true);
 
  cell_outline_color = sgetpar(fp, "cell_outline_color", "forestgreen", true);
 
  resize_stride = igetpar(fp, "resize_stride", 10, true);
 
  T = fgetpar(fp, "T", 1.0, true);
 
  lambda_length = fgetpar(fp, "lambda_length", 100., true);
 
  lambda_celllength = fgetpar(fp, "lambda_celllength", 0., true);
 
  target_length = fgetpar(fp, "target_length", 60., true);
 
  cell_expansion_rate = fgetpar(fp, "cell_expansion_rate", 1., true);
 
  cell_div_expansion_rate = fgetpar(fp, "cell_div_expansion_rate", 0., true);
 
  auxin_dependent_growth = bgetpar(fp, "auxin_dependent_growth", true, true);
 
  ode_accuracy = fgetpar(fp, "ode_accuracy", 1e-4, true);
 
  mc_stepsize = fgetpar(fp, "mc_stepsize", 0.4, true);
 
  mc_cell_stepsize = fgetpar(fp, "mc_cell_stepsize", 0.2, true);
 
  energy_threshold = fgetpar(fp, "energy_threshold", 1000., true);
 
  bend_lambda = fgetpar(fp, "bend_lambda", 0., true);
 
  alignment_lambda = fgetpar(fp, "alignment_lambda", 0., true);
 
  rel_cell_div_threshold = fgetpar(fp, "rel_cell_div_threshold", 2., true);
 
  rel_perimeter_stiffness = fgetpar(fp, "rel_perimeter_stiffness", 2, true);
 
  collapse_node_threshold = fgetpar(fp, "collapse_node_threshold", 0.05, true);
 
  morphogen_div_threshold = fgetpar(fp, "morphogen_div_threshold", 0.2, true);
 
  morphogen_expansion_threshold = fgetpar(fp, "morphogen_expansion_threshold", 0.01, true);
 
  copy_wall = bgetpar(fp, "copy_wall", true, true);
 
  source = fgetpar(fp, "source", 0., true);
 
  D = dgetparlist(fp, "D", 15, true);
 
  initval = dgetparlist(fp, "initval", 15, true);
 
  k1 = fgetpar(fp, "k1", 1., true);
 
  k2 = fgetpar(fp, "k2", 0.3, true);
 
  r = fgetpar(fp, "r", 1., true);
 
  kr = fgetpar(fp, "kr", 1., true);
 
  km = fgetpar(fp, "km", 1., true);
 
  Pi_tot = fgetpar(fp, "Pi_tot", 1., true);
 
  transport = fgetpar(fp, "transport", 0.036, true);
 
  ka = fgetpar(fp, "ka", 1, true);
 
  pin_prod = fgetpar(fp, "pin_prod", 0.001, true);
 
  pin_prod_in_epidermis = fgetpar(fp, "pin_prod_in_epidermis", 0.1, true);
 
  pin_breakdown = fgetpar(fp, "pin_breakdown", 0.001, true);
 
  pin_breakdown_internal = fgetpar(fp, "pin_breakdown_internal", 0.001, true);
 
  aux1prod = fgetpar(fp, "aux1prod", 0.001, true);
 
  aux1prodmeso = fgetpar(fp, "aux1prodmeso", 0., true);
 
  aux1decay = fgetpar(fp, "aux1decay", 0.001, true);
 
  aux1decaymeso = fgetpar(fp, "aux1decaymeso", 0.1, true);
 
  aux1transport = fgetpar(fp, "aux1transport", 0.036, true);
 
  aux_cons = fgetpar(fp, "aux_cons", 0., true);
 
  aux_breakdown = fgetpar(fp, "aux_breakdown", 0., true);
 
  kaux1 = fgetpar(fp, "kaux1", 1, true);
 
  kap = fgetpar(fp, "kap", 1, true);
 
  leaf_tip_source = fgetpar(fp, "leaf_tip_source", 0.001, true);
 
  sam_efflux = fgetpar(fp, "sam_efflux", 0.0001, true);
 
  sam_auxin = fgetpar(fp, "sam_auxin", 10., true);
 
  sam_auxin_breakdown = fgetpar(fp, "sam_auxin_breakdown", 0, true);
 
  van3prod = fgetpar(fp, "van3prod", 0.002, true);
 
  van3autokat = fgetpar(fp, "van3autokat", 0.1, true);
 
  van3sat = fgetpar(fp, "van3sat", 10, true);
 
  k2van3 = fgetpar(fp, "k2van3", 0.3, true);
 
  dt = fgetpar(fp, "dt", 0.1, true);
 
  rd_dt = fgetpar(fp, "rd_dt", 1.0, true);
 
  datadir = sgetpar(fp, "datadir", ".", true);
 
  if (strcmp(datadir, "."))
 
    MakeDir(datadir);
 
  movie = bgetpar(fp, "movie", false, true);
 
  nit = igetpar(fp, "nit", 100000, true);
 
  maxt = fgetpar(fp, "maxt", 1000., true);
 
  storage_stride = igetpar(fp, "storage_stride", 10, true);
 
  xml_storage_stride = igetpar(fp, "xml_storage_stride", 500, true);
 
  rseed = igetpar(fp, "rseed", -1, true);
 
  constituous_expansion_limit = igetpar(fp, "constituous_expansion_limit", 16, true);
 
  vessel_inh_level = fgetpar(fp, "vessel_inh_level", 1, true);
 
  vessel_expansion_rate = fgetpar(fp, "vessel_expansion_rate", 0.25, true);
 
  d = fgetpar(fp, "d", 0., true);
 
  e = fgetpar(fp, "e", 0., true);
 
  f = fgetpar(fp, "f", 0., true);
 
  c = fgetpar(fp, "c", 0., true);
 
  mu = fgetpar(fp, "mu", 0., true);
 
  nu = fgetpar(fp, "nu", 0., true);
 
  rho0 = fgetpar(fp, "rho0", 0., true);
 
  rho1 = fgetpar(fp, "rho1", 0., true);
 
  c0 = fgetpar(fp, "c0", 0., true);
 
  gamma = fgetpar(fp, "gamma", 0., true);
 
  eps = fgetpar(fp, "eps", 0., true);
 
  k = dgetparlist(fp, "k", 15, true);
 
  i1 = igetpar(fp, "i1", 0, true);
 
  i2 = igetpar(fp, "i2", 0, true);
 
  i3 = igetpar(fp, "i3", 0, true);
 
  i4 = igetpar(fp, "i4", 0, true);
 
  i5 = igetpar(fp, "i5", 0, true);
 
  s1 = sgetpar(fp, "s1", "", true);
 
  s2 = sgetpar(fp, "s2", "", true);
 
  s3 = sgetpar(fp, "s3", "", true);
 
  b1 = bgetpar(fp, "b1", false, true);
 
  b2 = bgetpar(fp, "b2", false, true);
 
  b3 = bgetpar(fp, "b3", false, true);
 
  b4 = bgetpar(fp, "b4", false, true);
 
  dir1 = sgetpar(fp, "dir1", ".", true);
 
  if (strcmp(dir1, "."))
 
    MakeDir(dir1);
 
  dir2 = sgetpar(fp, "dir2", ".", true);
 
  if (strcmp(dir2, "."))
 
    MakeDir(dir2);
 

	
 
}
 

	
 
const char *sbool(const bool &p) {
 

	
 
  const char *true_str="true";
 
  const char *false_str="false";
 
  if (p)
 
    return true_str;
 
  else
 
    return false_str;
 
}
 

	
 
void Parameter::Write(ostream &os) const {
 

	
 

	
 
  if (arrowcolor) 
 
    os << " arrowcolor = " << arrowcolor << endl;
 
  os << " arrowsize = " << arrowsize << endl;
 

	
 
  if (textcolor) 
 
    os << " textcolor = " << textcolor << endl;
 
  os << " cellnumsize = " << cellnumsize << endl;
 
  os << " nodenumsize = " << nodenumsize << endl;
 
  os << " node_mag = " << node_mag << endl;
 
  os << " outlinewidth = " << outlinewidth << endl;
 

	
 
  if (cell_outline_color) 
 
    os << " cell_outline_color = " << cell_outline_color << endl;
 
  os << " resize_stride = " << resize_stride << endl;
 
  os << " T = " << T << endl;
 
  os << " lambda_length = " << lambda_length << endl;
 
  os << " lambda_celllength = " << lambda_celllength << endl;
 
  os << " target_length = " << target_length << endl;
 
  os << " cell_expansion_rate = " << cell_expansion_rate << endl;
 
  os << " cell_div_expansion_rate = " << cell_div_expansion_rate << endl;
 
  os << " auxin_dependent_growth = " << sbool(auxin_dependent_growth) << endl;
 
  os << " ode_accuracy = " << ode_accuracy << endl;
 
  os << " mc_stepsize = " << mc_stepsize << endl;
 
  os << " mc_cell_stepsize = " << mc_cell_stepsize << endl;
 
  os << " energy_threshold = " << energy_threshold << endl;
 
  os << " bend_lambda = " << bend_lambda << endl;
 
  os << " alignment_lambda = " << alignment_lambda << endl;
 
  os << " rel_cell_div_threshold = " << rel_cell_div_threshold << endl;
 
  os << " rel_perimeter_stiffness = " << rel_perimeter_stiffness << endl;
 
  os << " collapse_node_threshold = " << collapse_node_threshold << endl;
 
  os << " morphogen_div_threshold = " << morphogen_div_threshold << endl;
 
  os << " morphogen_expansion_threshold = " << morphogen_expansion_threshold << endl;
 
  os << " copy_wall = " << sbool(copy_wall) << endl;
 
  os << " source = " << source << endl;
 
  os << " D = "<< D[0] << ", " << D[1] << ", " << D[2] << ", " << D[3] << ", " << D[4] << ", " << D[5] << ", " << D[6] << ", " << D[7] << ", " << D[8] << ", " << D[9] << ", " << D[10] << ", " << D[11] << ", " << D[12] << ", " << D[13] << ", " << D[14] << endl;
 
  os << " initval = "<< initval[0] << ", " << initval[1] << ", " << initval[2] << ", " << initval[3] << ", " << initval[4] << ", " << initval[5] << ", " << initval[6] << ", " << initval[7] << ", " << initval[8] << ", " << initval[9] << ", " << initval[10] << ", " << initval[11] << ", " << initval[12] << ", " << initval[13] << ", " << initval[14] << endl;
 
  os << " k1 = " << k1 << endl;
 
  os << " k2 = " << k2 << endl;
 
  os << " r = " << r << endl;
 
  os << " kr = " << kr << endl;
 
  os << " km = " << km << endl;
 
  os << " Pi_tot = " << Pi_tot << endl;
 
  os << " transport = " << transport << endl;
 
  os << " ka = " << ka << endl;
 
  os << " pin_prod = " << pin_prod << endl;
 
  os << " pin_prod_in_epidermis = " << pin_prod_in_epidermis << endl;
 
  os << " pin_breakdown = " << pin_breakdown << endl;
 
  os << " pin_breakdown_internal = " << pin_breakdown_internal << endl;
 
  os << " aux1prod = " << aux1prod << endl;
 
  os << " aux1prodmeso = " << aux1prodmeso << endl;
 
  os << " aux1decay = " << aux1decay << endl;
 
  os << " aux1decaymeso = " << aux1decaymeso << endl;
 
  os << " aux1transport = " << aux1transport << endl;
 
  os << " aux_cons = " << aux_cons << endl;
 
  os << " aux_breakdown = " << aux_breakdown << endl;
 
  os << " kaux1 = " << kaux1 << endl;
 
  os << " kap = " << kap << endl;
 
  os << " leaf_tip_source = " << leaf_tip_source << endl;
 
  os << " sam_efflux = " << sam_efflux << endl;
 
  os << " sam_auxin = " << sam_auxin << endl;
 
  os << " sam_auxin_breakdown = " << sam_auxin_breakdown << endl;
 
  os << " van3prod = " << van3prod << endl;
 
  os << " van3autokat = " << van3autokat << endl;
 
  os << " van3sat = " << van3sat << endl;
 
  os << " k2van3 = " << k2van3 << endl;
 
  os << " dt = " << dt << endl;
 
  os << " rd_dt = " << rd_dt << endl;
 

	
 
  if (datadir) 
 
    os << " datadir = " << datadir << endl;
 
  os << " movie = " << sbool(movie) << endl;
 
  os << " nit = " << nit << endl;
 
  os << " maxt = " << maxt << endl;
 
  os << " storage_stride = " << storage_stride << endl;
 
  os << " xml_storage_stride = " << xml_storage_stride << endl;
 
  os << " rseed = " << rseed << endl;
 
  os << " constituous_expansion_limit = " << constituous_expansion_limit << endl;
 
  os << " vessel_inh_level = " << vessel_inh_level << endl;
 
  os << " vessel_expansion_rate = " << vessel_expansion_rate << endl;
 
  os << " d = " << d << endl;
 
  os << " e = " << e << endl;
 
  os << " f = " << f << endl;
 
  os << " c = " << c << endl;
 
  os << " mu = " << mu << endl;
 
  os << " nu = " << nu << endl;
 
  os << " rho0 = " << rho0 << endl;
 
  os << " rho1 = " << rho1 << endl;
 
  os << " c0 = " << c0 << endl;
 
  os << " gamma = " << gamma << endl;
 
  os << " eps = " << eps << endl;
 
  os << " k = "<< k[0] << ", " << k[1] << ", " << k[2] << ", " << k[3] << ", " << k[4] << ", " << k[5] << ", " << k[6] << ", " << k[7] << ", " << k[8] << ", " << k[9] << ", " << k[10] << ", " << k[11] << ", " << k[12] << ", " << k[13] << ", " << k[14] << endl;
 
  os << " i1 = " << i1 << endl;
 
  os << " i2 = " << i2 << endl;
 
  os << " i3 = " << i3 << endl;
 
  os << " i4 = " << i4 << endl;
 
  os << " i5 = " << i5 << endl;
 

	
 
  if (s1) 
 
    os << " s1 = " << s1 << endl;
 

	
 
  if (s2) 
 
    os << " s2 = " << s2 << endl;
 

	
 
  if (s3) 
 
    os << " s3 = " << s3 << endl;
 
  os << " b1 = " << sbool(b1) << endl;
 
  os << " b2 = " << sbool(b2) << endl;
 
  os << " b3 = " << sbool(b3) << endl;
 
  os << " b4 = " << sbool(b4) << endl;
 

	
 
  if (dir1) 
 
    os << " dir1 = " << dir1 << endl;
 

	
 
  if (dir2) 
 
    os << " dir2 = " << dir2 << endl;
 
}
 
void Parameter::XMLAdd(xmlNode *root) const {
 
  xmlNode *xmlparameter = xmlNewChild(root, NULL, BAD_CAST "parameter", NULL);
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "arrowcolor" );
 
  ostringstream text;
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "arrowcolor" );
 
    ostringstream text;
 

	
 
  if (arrowcolor) 
 
    text << arrowcolor;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "arrowsize" );
 
  ostringstream text;
 
  text << arrowsize;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "textcolor" );
 
  ostringstream text;
 
    if (arrowcolor) 
 
      text << arrowcolor;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "arrowsize" );
 
    ostringstream text;
 
    text << arrowsize;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "textcolor" );
 
    ostringstream text;
 

	
 
  if (textcolor) 
 
    text << textcolor;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "cellnumsize" );
 
  ostringstream text;
 
  text << cellnumsize;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "nodenumsize" );
 
  ostringstream text;
 
  text << nodenumsize;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "node_mag" );
 
  ostringstream text;
 
  text << node_mag;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "outlinewidth" );
 
  ostringstream text;
 
  text << outlinewidth;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "cell_outline_color" );
 
  ostringstream text;
 
    if (textcolor) 
 
      text << textcolor;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "cellnumsize" );
 
    ostringstream text;
 
    text << cellnumsize;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "nodenumsize" );
 
    ostringstream text;
 
    text << nodenumsize;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "node_mag" );
 
    ostringstream text;
 
    text << node_mag;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "outlinewidth" );
 
    ostringstream text;
 
    text << outlinewidth;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "cell_outline_color" );
 
    ostringstream text;
 

	
 
  if (cell_outline_color) 
 
    text << cell_outline_color;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "resize_stride" );
 
  ostringstream text;
 
  text << resize_stride;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "T" );
 
  ostringstream text;
 
  text << T;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "lambda_length" );
 
  ostringstream text;
 
  text << lambda_length;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "lambda_celllength" );
 
  ostringstream text;
 
  text << lambda_celllength;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "target_length" );
 
  ostringstream text;
 
  text << target_length;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "cell_expansion_rate" );
 
  ostringstream text;
 
  text << cell_expansion_rate;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "cell_div_expansion_rate" );
 
  ostringstream text;
 
  text << cell_div_expansion_rate;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "auxin_dependent_growth" );
 
  ostringstream text;
 
text << sbool(auxin_dependent_growth);
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "ode_accuracy" );
 
  ostringstream text;
 
  text << ode_accuracy;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "mc_stepsize" );
 
  ostringstream text;
 
  text << mc_stepsize;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "mc_cell_stepsize" );
 
  ostringstream text;
 
  text << mc_cell_stepsize;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "energy_threshold" );
 
  ostringstream text;
 
  text << energy_threshold;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "bend_lambda" );
 
  ostringstream text;
 
  text << bend_lambda;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "alignment_lambda" );
 
  ostringstream text;
 
  text << alignment_lambda;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "rel_cell_div_threshold" );
 
  ostringstream text;
 
  text << rel_cell_div_threshold;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "rel_perimeter_stiffness" );
 
  ostringstream text;
 
  text << rel_perimeter_stiffness;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "collapse_node_threshold" );
 
  ostringstream text;
 
  text << collapse_node_threshold;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "morphogen_div_threshold" );
 
  ostringstream text;
 
  text << morphogen_div_threshold;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "morphogen_expansion_threshold" );
 
  ostringstream text;
 
  text << morphogen_expansion_threshold;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "copy_wall" );
 
  ostringstream text;
 
text << sbool(copy_wall);
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "source" );
 
  ostringstream text;
 
  text << source;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "D" );
 
  xmlNode *xmlvalarray = xmlNewChild(xmlpar, NULL, BAD_CAST "valarray", NULL);
 
    if (cell_outline_color) 
 
      text << cell_outline_color;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "resize_stride" );
 
    ostringstream text;
 
    text << resize_stride;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "T" );
 
    ostringstream text;
 
    text << T;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "lambda_length" );
 
    ostringstream text;
 
    text << lambda_length;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "lambda_celllength" );
 
    ostringstream text;
 
    text << lambda_celllength;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "target_length" );
 
    ostringstream text;
 
    text << target_length;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "cell_expansion_rate" );
 
    ostringstream text;
 
    text << cell_expansion_rate;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "cell_div_expansion_rate" );
 
    ostringstream text;
 
    text << cell_div_expansion_rate;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "auxin_dependent_growth" );
 
    ostringstream text;
 
    text << sbool(auxin_dependent_growth);
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "ode_accuracy" );
 
    ostringstream text;
 
    text << ode_accuracy;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "mc_stepsize" );
 
    ostringstream text;
 
    text << mc_stepsize;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "mc_cell_stepsize" );
 
    ostringstream text;
 
    text << D[0];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    text << mc_cell_stepsize;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "energy_threshold" );
 
    ostringstream text;
 
    text << energy_threshold;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "bend_lambda" );
 
    ostringstream text;
 
    text << bend_lambda;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "alignment_lambda" );
 
    ostringstream text;
 
    text << alignment_lambda;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "rel_cell_div_threshold" );
 
    ostringstream text;
 
    text << rel_cell_div_threshold;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "rel_perimeter_stiffness" );
 
    ostringstream text;
 
    text << rel_perimeter_stiffness;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "collapse_node_threshold" );
 
    ostringstream text;
 
    text << collapse_node_threshold;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "morphogen_div_threshold" );
 
    ostringstream text;
 
    text << morphogen_div_threshold;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "morphogen_expansion_threshold" );
 
    ostringstream text;
 
    text << morphogen_expansion_threshold;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "copy_wall" );
 
    ostringstream text;
 
    text << sbool(copy_wall);
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "source" );
 
    ostringstream text;
 
    text << source;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << D[1];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << D[2];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << D[3];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << D[4];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << D[5];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << D[6];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << D[7];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << D[8];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << D[9];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << D[10];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << D[11];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << D[12];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << D[13];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "D" );
 
    xmlNode *xmlvalarray = xmlNewChild(xmlpar, NULL, BAD_CAST "valarray", NULL);
 
    {
 
      ostringstream text;
 
      text << D[0];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << D[1];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << D[2];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << D[3];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << D[4];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << D[5];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << D[6];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << D[7];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << D[8];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << D[9];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << D[10];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << D[11];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << D[12];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << D[13];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << D[14];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
  }
 
  {
 
    ostringstream text;
 
    text << D[14];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "initval" );
 
  xmlNode *xmlvalarray = xmlNewChild(xmlpar, NULL, BAD_CAST "valarray", NULL);
 
  {
 
    ostringstream text;
 
    text << initval[0];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << initval[1];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << initval[2];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << initval[3];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << initval[4];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << initval[5];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "initval" );
 
    xmlNode *xmlvalarray = xmlNewChild(xmlpar, NULL, BAD_CAST "valarray", NULL);
 
    {
 
      ostringstream text;
 
      text << initval[0];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << initval[1];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << initval[2];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << initval[3];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << initval[4];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << initval[5];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << initval[6];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << initval[7];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << initval[8];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << initval[9];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << initval[10];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << initval[11];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << initval[12];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << initval[13];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << initval[14];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "k1" );
 
    ostringstream text;
 
    text << initval[6];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    text << k1;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "k2" );
 
    ostringstream text;
 
    text << k2;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "r" );
 
    ostringstream text;
 
    text << initval[7];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    text << r;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "kr" );
 
    ostringstream text;
 
    text << initval[8];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    text << kr;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "km" );
 
    ostringstream text;
 
    text << km;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "Pi_tot" );
 
    ostringstream text;
 
    text << initval[9];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    text << Pi_tot;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "transport" );
 
    ostringstream text;
 
    text << initval[10];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    text << transport;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "ka" );
 
    ostringstream text;
 
    text << ka;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "pin_prod" );
 
    ostringstream text;
 
    text << initval[11];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    text << pin_prod;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "pin_prod_in_epidermis" );
 
    ostringstream text;
 
    text << initval[12];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    text << pin_prod_in_epidermis;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "pin_breakdown" );
 
    ostringstream text;
 
    text << initval[13];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    text << pin_breakdown;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "pin_breakdown_internal" );
 
    ostringstream text;
 
    text << pin_breakdown_internal;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "aux1prod" );
 
    ostringstream text;
 
    text << initval[14];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    text << aux1prod;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "aux1prodmeso" );
 
    ostringstream text;
 
    text << aux1prodmeso;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "aux1decay" );
 
    ostringstream text;
 
    text << aux1decay;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "aux1decaymeso" );
 
    ostringstream text;
 
    text << aux1decaymeso;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "aux1transport" );
 
    ostringstream text;
 
    text << aux1transport;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "aux_cons" );
 
    ostringstream text;
 
    text << aux_cons;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "aux_breakdown" );
 
    ostringstream text;
 
    text << aux_breakdown;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "kaux1" );
 
    ostringstream text;
 
    text << kaux1;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "kap" );
 
    ostringstream text;
 
    text << kap;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "leaf_tip_source" );
 
    ostringstream text;
 
    text << leaf_tip_source;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "sam_efflux" );
 
    ostringstream text;
 
    text << sam_efflux;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "sam_auxin" );
 
    ostringstream text;
 
    text << sam_auxin;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "sam_auxin_breakdown" );
 
    ostringstream text;
 
    text << sam_auxin_breakdown;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "van3prod" );
 
    ostringstream text;
 
    text << van3prod;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "van3autokat" );
 
    ostringstream text;
 
    text << van3autokat;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "van3sat" );
 
    ostringstream text;
 
    text << van3sat;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "k2van3" );
 
    ostringstream text;
 
    text << k2van3;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "k1" );
 
  ostringstream text;
 
  text << k1;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "k2" );
 
  ostringstream text;
 
  text << k2;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "r" );
 
  ostringstream text;
 
  text << r;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "kr" );
 
  ostringstream text;
 
  text << kr;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "km" );
 
  ostringstream text;
 
  text << km;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "Pi_tot" );
 
  ostringstream text;
 
  text << Pi_tot;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "transport" );
 
  ostringstream text;
 
  text << transport;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "ka" );
 
  ostringstream text;
 
  text << ka;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "pin_prod" );
 
  ostringstream text;
 
  text << pin_prod;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "pin_prod_in_epidermis" );
 
  ostringstream text;
 
  text << pin_prod_in_epidermis;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "pin_breakdown" );
 
  ostringstream text;
 
  text << pin_breakdown;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "pin_breakdown_internal" );
 
  ostringstream text;
 
  text << pin_breakdown_internal;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "aux1prod" );
 
  ostringstream text;
 
  text << aux1prod;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "aux1prodmeso" );
 
  ostringstream text;
 
  text << aux1prodmeso;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "aux1decay" );
 
  ostringstream text;
 
  text << aux1decay;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "aux1decaymeso" );
 
  ostringstream text;
 
  text << aux1decaymeso;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "aux1transport" );
 
  ostringstream text;
 
  text << aux1transport;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "aux_cons" );
 
  ostringstream text;
 
  text << aux_cons;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "aux_breakdown" );
 
  ostringstream text;
 
  text << aux_breakdown;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "kaux1" );
 
  ostringstream text;
 
  text << kaux1;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "kap" );
 
  ostringstream text;
 
  text << kap;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "leaf_tip_source" );
 
  ostringstream text;
 
  text << leaf_tip_source;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "sam_efflux" );
 
  ostringstream text;
 
  text << sam_efflux;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "sam_auxin" );
 
  ostringstream text;
 
  text << sam_auxin;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "sam_auxin_breakdown" );
 
  ostringstream text;
 
  text << sam_auxin_breakdown;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "van3prod" );
 
  ostringstream text;
 
  text << van3prod;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "van3autokat" );
 
  ostringstream text;
 
  text << van3autokat;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "van3sat" );
 
  ostringstream text;
 
  text << van3sat;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "k2van3" );
 
  ostringstream text;
 
  text << k2van3;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "dt" );
 
  ostringstream text;
 
  text << dt;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "rd_dt" );
 
  ostringstream text;
 
  text << rd_dt;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "datadir" );
 
  ostringstream text;
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "dt" );
 
    ostringstream text;
 
    text << dt;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "rd_dt" );
 
    ostringstream text;
 
    text << rd_dt;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "datadir" );
 
    ostringstream text;
 

	
 
  if (datadir) 
 
    text << datadir;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "movie" );
 
  ostringstream text;
 
text << sbool(movie);
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "nit" );
 
  ostringstream text;
 
  text << nit;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "maxt" );
 
  ostringstream text;
 
  text << maxt;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "storage_stride" );
 
  ostringstream text;
 
  text << storage_stride;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "xml_storage_stride" );
 
  ostringstream text;
 
  text << xml_storage_stride;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "rseed" );
 
  ostringstream text;
 
  text << rseed;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "constituous_expansion_limit" );
 
  ostringstream text;
 
  text << constituous_expansion_limit;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "vessel_inh_level" );
 
  ostringstream text;
 
  text << vessel_inh_level;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "vessel_expansion_rate" );
 
  ostringstream text;
 
  text << vessel_expansion_rate;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "d" );
 
  ostringstream text;
 
  text << d;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "e" );
 
  ostringstream text;
 
  text << e;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "f" );
 
  ostringstream text;
 
  text << f;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "c" );
 
  ostringstream text;
 
  text << c;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "mu" );
 
  ostringstream text;
 
  text << mu;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "nu" );
 
  ostringstream text;
 
  text << nu;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "rho0" );
 
  ostringstream text;
 
  text << rho0;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "rho1" );
 
  ostringstream text;
 
  text << rho1;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "c0" );
 
  ostringstream text;
 
  text << c0;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "gamma" );
 
  ostringstream text;
 
  text << gamma;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "eps" );
 
  ostringstream text;
 
  text << eps;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "k" );
 
  xmlNode *xmlvalarray = xmlNewChild(xmlpar, NULL, BAD_CAST "valarray", NULL);
 
    if (datadir) 
 
      text << datadir;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "movie" );
 
    ostringstream text;
 
    text << sbool(movie);
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "nit" );
 
    ostringstream text;
 
    text << nit;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "maxt" );
 
    ostringstream text;
 
    text << maxt;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "storage_stride" );
 
    ostringstream text;
 
    text << storage_stride;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "xml_storage_stride" );
 
    ostringstream text;
 
    text << xml_storage_stride;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "rseed" );
 
    ostringstream text;
 
    text << rseed;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "constituous_expansion_limit" );
 
    ostringstream text;
 
    text << k[0];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    text << constituous_expansion_limit;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "vessel_inh_level" );
 
    ostringstream text;
 
    text << vessel_inh_level;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "vessel_expansion_rate" );
 
    ostringstream text;
 
    text << vessel_expansion_rate;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "d" );
 
    ostringstream text;
 
    text << d;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "e" );
 
    ostringstream text;
 
    text << e;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "f" );
 
    ostringstream text;
 
    text << f;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "c" );
 
    ostringstream text;
 
    text << c;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "mu" );
 
    ostringstream text;
 
    text << mu;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "nu" );
 
    ostringstream text;
 
    text << k[1];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << k[2];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    text << nu;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << k[3];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "rho0" );
 
    ostringstream text;
 
    text << k[4];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << k[5];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << k[6];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    text << rho0;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << k[7];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "rho1" );
 
    ostringstream text;
 
    text << k[8];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << k[9];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    text << rho1;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "c0" );
 
    ostringstream text;
 
    text << k[10];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    text << c0;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "gamma" );
 
    ostringstream text;
 
    text << k[11];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    text << gamma;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "eps" );
 
    ostringstream text;
 
    text << k[12];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << k[13];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    text << eps;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << k[14];
 
    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
    xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "k" );
 
    xmlNode *xmlvalarray = xmlNewChild(xmlpar, NULL, BAD_CAST "valarray", NULL);
 
    {
 
      ostringstream text;
 
      text << k[0];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << k[1];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << k[2];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << k[3];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << k[4];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << k[5];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << k[6];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << k[7];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << k[8];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << k[9];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << k[10];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << k[11];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << k[12];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << k[13];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
    {
 
      ostringstream text;
 
      text << k[14];
 
      xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST "val", NULL);
 
      xmlNewProp(xmlval, BAD_CAST "v", BAD_CAST text.str().c_str());
 
    }
 
  }
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "i1" );
 
  ostringstream text;
 
  text << i1;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "i2" );
 
  ostringstream text;
 
  text << i2;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "i3" );
 
  ostringstream text;
 
  text << i3;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "i4" );
 
  ostringstream text;
 
  text << i4;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "i5" );
 
  ostringstream text;
 
  text << i5;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "s1" );
 
  ostringstream text;
 

	
 
  if (s1) 
 
    text << s1;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "s2" );
 
  ostringstream text;
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "i1" );
 
    ostringstream text;
 
    text << i1;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "i2" );
 
    ostringstream text;
 
    text << i2;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "i3" );
 
    ostringstream text;
 
    text << i3;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "i4" );
 
    ostringstream text;
 
    text << i4;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "i5" );
 
    ostringstream text;
 
    text << i5;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "s1" );
 
    ostringstream text;
 

	
 
  if (s2) 
 
    text << s2;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "s3" );
 
  ostringstream text;
 
    if (s1) 
 
      text << s1;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "s2" );
 
    ostringstream text;
 

	
 
    if (s2) 
 
      text << s2;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "s3" );
 
    ostringstream text;
 

	
 
  if (s3) 
 
    text << s3;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "b1" );
 
  ostringstream text;
 
text << sbool(b1);
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "b2" );
 
  ostringstream text;
 
text << sbool(b2);
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "b3" );
 
  ostringstream text;
 
text << sbool(b3);
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "b4" );
 
  ostringstream text;
 
text << sbool(b4);
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "dir1" );
 
  ostringstream text;
 
    if (s3) 
 
      text << s3;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "b1" );
 
    ostringstream text;
 
    text << sbool(b1);
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "b2" );
 
    ostringstream text;
 
    text << sbool(b2);
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "b3" );
 
    ostringstream text;
 
    text << sbool(b3);
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "b4" );
 
    ostringstream text;
 
    text << sbool(b4);
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "dir1" );
 
    ostringstream text;
 

	
 
  if (dir1) 
 
    text << dir1;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
{
 
  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
  xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "dir2" );
 
  ostringstream text;
 
    if (dir1) 
 
      text << dir1;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST "par", NULL);
 
    xmlNewProp(xmlpar, BAD_CAST "name", BAD_CAST "dir2" );
 
    ostringstream text;
 

	
 
  if (dir2) 
 
    text << dir2;
 
xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
}
 
    if (dir2) 
 
      text << dir2;
 
    xmlNewProp(xmlpar, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
}
 
void Parameter::AssignValToPar(const char *namec, const char *valc) {
 
  QLocale standardlocale(QLocale::C);
 
  bool ok;
 
if (!strcmp(namec, "arrowcolor")) {
 
  if (arrowcolor) { free(arrowcolor); }
 
  arrowcolor=strdup(valc);
 
}
 
if (!strcmp(namec, "arrowsize")) {
 
  arrowsize = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'arrowsize' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "textcolor")) {
 
  if (textcolor) { free(textcolor); }
 
  textcolor=strdup(valc);
 
}
 
if (!strcmp(namec, "cellnumsize")) {
 
  cellnumsize = standardlocale.toInt(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'cellnumsize' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "nodenumsize")) {
 
  nodenumsize = standardlocale.toInt(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'nodenumsize' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "node_mag")) {
 
  node_mag = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'node_mag' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "outlinewidth")) {
 
  outlinewidth = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'outlinewidth' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "cell_outline_color")) {
 
  if (cell_outline_color) { free(cell_outline_color); }
 
  cell_outline_color=strdup(valc);
 
}
 
if (!strcmp(namec, "resize_stride")) {
 
  resize_stride = standardlocale.toInt(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'resize_stride' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "T")) {
 
  T = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'T' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "lambda_length")) {
 
  lambda_length = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'lambda_length' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "lambda_celllength")) {
 
  lambda_celllength = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'lambda_celllength' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "target_length")) {
 
  target_length = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'target_length' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "cell_expansion_rate")) {
 
  cell_expansion_rate = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'cell_expansion_rate' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "cell_div_expansion_rate")) {
 
  cell_div_expansion_rate = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'cell_div_expansion_rate' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "auxin_dependent_growth")) {
 
auxin_dependent_growth = strtobool(valc);
 
}
 
if (!strcmp(namec, "ode_accuracy")) {
 
  ode_accuracy = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'ode_accuracy' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "mc_stepsize")) {
 
  mc_stepsize = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'mc_stepsize' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "mc_cell_stepsize")) {
 
  mc_cell_stepsize = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'mc_cell_stepsize' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "energy_threshold")) {
 
  energy_threshold = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'energy_threshold' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "bend_lambda")) {
 
  bend_lambda = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'bend_lambda' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "alignment_lambda")) {
 
  alignment_lambda = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'alignment_lambda' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "rel_cell_div_threshold")) {
 
  rel_cell_div_threshold = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'rel_cell_div_threshold' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "rel_perimeter_stiffness")) {
 
  rel_perimeter_stiffness = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'rel_perimeter_stiffness' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "collapse_node_threshold")) {
 
  collapse_node_threshold = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'collapse_node_threshold' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "morphogen_div_threshold")) {
 
  morphogen_div_threshold = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'morphogen_div_threshold' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "morphogen_expansion_threshold")) {
 
  morphogen_expansion_threshold = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'morphogen_expansion_threshold' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "copy_wall")) {
 
copy_wall = strtobool(valc);
 
}
 
if (!strcmp(namec, "source")) {
 
  source = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'source' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "k1")) {
 
  k1 = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'k1' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "k2")) {
 
  k2 = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'k2' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "r")) {
 
  r = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'r' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "kr")) {
 
  kr = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'kr' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "km")) {
 
  km = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'km' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "Pi_tot")) {
 
  Pi_tot = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'Pi_tot' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "transport")) {
 
  transport = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'transport' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "ka")) {
 
  ka = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'ka' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "pin_prod")) {
 
  pin_prod = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'pin_prod' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "pin_prod_in_epidermis")) {
 
  pin_prod_in_epidermis = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'pin_prod_in_epidermis' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "pin_breakdown")) {
 
  pin_breakdown = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'pin_breakdown' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "pin_breakdown_internal")) {
 
  pin_breakdown_internal = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'pin_breakdown_internal' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "aux1prod")) {
 
  aux1prod = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'aux1prod' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "aux1prodmeso")) {
 
  aux1prodmeso = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'aux1prodmeso' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "aux1decay")) {
 
  aux1decay = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'aux1decay' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "aux1decaymeso")) {
 
  aux1decaymeso = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'aux1decaymeso' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "aux1transport")) {
 
  aux1transport = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'aux1transport' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "aux_cons")) {
 
  aux_cons = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'aux_cons' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "aux_breakdown")) {
 
  aux_breakdown = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'aux_breakdown' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "kaux1")) {
 
  kaux1 = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'kaux1' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "kap")) {
 
  kap = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'kap' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "leaf_tip_source")) {
 
  leaf_tip_source = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'leaf_tip_source' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "sam_efflux")) {
 
  sam_efflux = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'sam_efflux' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "sam_auxin")) {
 
  sam_auxin = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'sam_auxin' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "sam_auxin_breakdown")) {
 
  sam_auxin_breakdown = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'sam_auxin_breakdown' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "van3prod")) {
 
  van3prod = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'van3prod' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "van3autokat")) {
 
  van3autokat = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'van3autokat' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "van3sat")) {
 
  van3sat = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'van3sat' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "k2van3")) {
 
  k2van3 = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'k2van3' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "dt")) {
 
  dt = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'dt' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "rd_dt")) {
 
  rd_dt = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'rd_dt' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "datadir")) {
 
  if (datadir) { free(datadir); }
 
  datadir=strdup(valc);
 
}
 
if (!strcmp(namec, "movie")) {
 
movie = strtobool(valc);
 
}
 
if (!strcmp(namec, "nit")) {
 
  nit = standardlocale.toInt(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'nit' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "maxt")) {
 
  maxt = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'maxt' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "storage_stride")) {
 
  storage_stride = standardlocale.toInt(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'storage_stride' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "xml_storage_stride")) {
 
  xml_storage_stride = standardlocale.toInt(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'xml_storage_stride' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "rseed")) {
 
  rseed = standardlocale.toInt(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'rseed' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "constituous_expansion_limit")) {
 
  constituous_expansion_limit = standardlocale.toInt(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'constituous_expansion_limit' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "vessel_inh_level")) {
 
  vessel_inh_level = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'vessel_inh_level' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "vessel_expansion_rate")) {
 
  vessel_expansion_rate = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'vessel_expansion_rate' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "d")) {
 
  d = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'd' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "e")) {
 
  e = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'e' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "f")) {
 
  f = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'f' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "c")) {
 
  c = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'c' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "mu")) {
 
  mu = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'mu' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "nu")) {
 
  nu = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'nu' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "rho0")) {
 
  rho0 = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'rho0' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "rho1")) {
 
  rho1 = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'rho1' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "c0")) {
 
  c0 = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'c0' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "gamma")) {
 
  gamma = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'gamma' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "eps")) {
 
  eps = standardlocale.toDouble(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'eps' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "i1")) {
 
  i1 = standardlocale.toInt(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'i1' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "i2")) {
 
  i2 = standardlocale.toInt(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'i2' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "i3")) {
 
  i3 = standardlocale.toInt(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'i3' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "i4")) {
 
  i4 = standardlocale.toInt(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'i4' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "i5")) {
 
  i5 = standardlocale.toInt(valc, &ok);
 
  if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'i5' from XML file.",valc); }
 
}
 
if (!strcmp(namec, "s1")) {
 
  if (s1) { free(s1); }
 
  s1=strdup(valc);
 
}
 
if (!strcmp(namec, "s2")) {
 
  if (s2) { free(s2); }
 
  s2=strdup(valc);
 
}
 
if (!strcmp(namec, "s3")) {
 
  if (s3) { free(s3); }
 
  s3=strdup(valc);
 
}
 
if (!strcmp(namec, "b1")) {
 
b1 = strtobool(valc);
 
}
 
if (!strcmp(namec, "b2")) {
 
b2 = strtobool(valc);
 
}
 
if (!strcmp(namec, "b3")) {
 
b3 = strtobool(valc);
 
}
 
if (!strcmp(namec, "b4")) {
 
b4 = strtobool(valc);
 
}
 
if (!strcmp(namec, "dir1")) {
 
  if (dir1) { free(dir1); }
 
  dir1=strdup(valc);
 
}
 
if (!strcmp(namec, "dir2")) {
 
  if (dir2) { free(dir2); }
 
  dir2=strdup(valc);
 
}
 
  if (!strcmp(namec, "arrowcolor")) {
 
    if (arrowcolor) { free(arrowcolor); }
 
    arrowcolor=strdup(valc);
 
  }
 
  if (!strcmp(namec, "arrowsize")) {
 
    arrowsize = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'arrowsize' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "textcolor")) {
 
    if (textcolor) { free(textcolor); }
 
    textcolor=strdup(valc);
 
  }
 
  if (!strcmp(namec, "cellnumsize")) {
 
    cellnumsize = standardlocale.toInt(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'cellnumsize' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "nodenumsize")) {
 
    nodenumsize = standardlocale.toInt(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'nodenumsize' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "node_mag")) {
 
    node_mag = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'node_mag' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "outlinewidth")) {
 
    outlinewidth = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'outlinewidth' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "cell_outline_color")) {
 
    if (cell_outline_color) { free(cell_outline_color); }
 
    cell_outline_color=strdup(valc);
 
  }
 
  if (!strcmp(namec, "resize_stride")) {
 
    resize_stride = standardlocale.toInt(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'resize_stride' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "T")) {
 
    T = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'T' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "lambda_length")) {
 
    lambda_length = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'lambda_length' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "lambda_celllength")) {
 
    lambda_celllength = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'lambda_celllength' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "target_length")) {
 
    target_length = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'target_length' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "cell_expansion_rate")) {
 
    cell_expansion_rate = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'cell_expansion_rate' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "cell_div_expansion_rate")) {
 
    cell_div_expansion_rate = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'cell_div_expansion_rate' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "auxin_dependent_growth")) {
 
    auxin_dependent_growth = strtobool(valc);
 
  }
 
  if (!strcmp(namec, "ode_accuracy")) {
 
    ode_accuracy = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'ode_accuracy' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "mc_stepsize")) {
 
    mc_stepsize = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'mc_stepsize' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "mc_cell_stepsize")) {
 
    mc_cell_stepsize = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'mc_cell_stepsize' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "energy_threshold")) {
 
    energy_threshold = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'energy_threshold' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "bend_lambda")) {
 
    bend_lambda = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'bend_lambda' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "alignment_lambda")) {
 
    alignment_lambda = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'alignment_lambda' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "rel_cell_div_threshold")) {
 
    rel_cell_div_threshold = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'rel_cell_div_threshold' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "rel_perimeter_stiffness")) {
 
    rel_perimeter_stiffness = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'rel_perimeter_stiffness' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "collapse_node_threshold")) {
 
    collapse_node_threshold = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'collapse_node_threshold' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "morphogen_div_threshold")) {
 
    morphogen_div_threshold = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'morphogen_div_threshold' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "morphogen_expansion_threshold")) {
 
    morphogen_expansion_threshold = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'morphogen_expansion_threshold' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "copy_wall")) {
 
    copy_wall = strtobool(valc);
 
  }
 
  if (!strcmp(namec, "source")) {
 
    source = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'source' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "k1")) {
 
    k1 = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'k1' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "k2")) {
 
    k2 = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'k2' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "r")) {
 
    r = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'r' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "kr")) {
 
    kr = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'kr' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "km")) {
 
    km = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'km' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "Pi_tot")) {
 
    Pi_tot = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'Pi_tot' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "transport")) {
 
    transport = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'transport' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "ka")) {
 
    ka = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'ka' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "pin_prod")) {
 
    pin_prod = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'pin_prod' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "pin_prod_in_epidermis")) {
 
    pin_prod_in_epidermis = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'pin_prod_in_epidermis' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "pin_breakdown")) {
 
    pin_breakdown = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'pin_breakdown' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "pin_breakdown_internal")) {
 
    pin_breakdown_internal = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'pin_breakdown_internal' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "aux1prod")) {
 
    aux1prod = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'aux1prod' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "aux1prodmeso")) {
 
    aux1prodmeso = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'aux1prodmeso' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "aux1decay")) {
 
    aux1decay = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'aux1decay' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "aux1decaymeso")) {
 
    aux1decaymeso = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'aux1decaymeso' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "aux1transport")) {
 
    aux1transport = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'aux1transport' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "aux_cons")) {
 
    aux_cons = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'aux_cons' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "aux_breakdown")) {
 
    aux_breakdown = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'aux_breakdown' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "kaux1")) {
 
    kaux1 = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'kaux1' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "kap")) {
 
    kap = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'kap' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "leaf_tip_source")) {
 
    leaf_tip_source = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'leaf_tip_source' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "sam_efflux")) {
 
    sam_efflux = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'sam_efflux' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "sam_auxin")) {
 
    sam_auxin = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'sam_auxin' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "sam_auxin_breakdown")) {
 
    sam_auxin_breakdown = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'sam_auxin_breakdown' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "van3prod")) {
 
    van3prod = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'van3prod' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "van3autokat")) {
 
    van3autokat = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'van3autokat' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "van3sat")) {
 
    van3sat = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'van3sat' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "k2van3")) {
 
    k2van3 = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'k2van3' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "dt")) {
 
    dt = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'dt' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "rd_dt")) {
 
    rd_dt = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'rd_dt' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "datadir")) {
 
    if (datadir) { free(datadir); }
 
    datadir=strdup(valc);
 
  }
 
  if (!strcmp(namec, "movie")) {
 
    movie = strtobool(valc);
 
  }
 
  if (!strcmp(namec, "nit")) {
 
    nit = standardlocale.toInt(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'nit' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "maxt")) {
 
    maxt = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'maxt' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "storage_stride")) {
 
    storage_stride = standardlocale.toInt(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'storage_stride' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "xml_storage_stride")) {
 
    xml_storage_stride = standardlocale.toInt(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'xml_storage_stride' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "rseed")) {
 
    rseed = standardlocale.toInt(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'rseed' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "constituous_expansion_limit")) {
 
    constituous_expansion_limit = standardlocale.toInt(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'constituous_expansion_limit' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "vessel_inh_level")) {
 
    vessel_inh_level = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'vessel_inh_level' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "vessel_expansion_rate")) {
 
    vessel_expansion_rate = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'vessel_expansion_rate' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "d")) {
 
    d = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'd' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "e")) {
 
    e = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'e' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "f")) {
 
    f = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'f' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "c")) {
 
    c = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'c' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "mu")) {
 
    mu = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'mu' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "nu")) {
 
    nu = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'nu' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "rho0")) {
 
    rho0 = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'rho0' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "rho1")) {
 
    rho1 = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'rho1' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "c0")) {
 
    c0 = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'c0' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "gamma")) {
 
    gamma = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'gamma' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "eps")) {
 
    eps = standardlocale.toDouble(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'eps' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "i1")) {
 
    i1 = standardlocale.toInt(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'i1' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "i2")) {
 
    i2 = standardlocale.toInt(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'i2' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "i3")) {
 
    i3 = standardlocale.toInt(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'i3' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "i4")) {
 
    i4 = standardlocale.toInt(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'i4' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "i5")) {
 
    i5 = standardlocale.toInt(valc, &ok);
 
    if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to integer while reading parameter 'i5' from XML file.",valc); }
 
  }
 
  if (!strcmp(namec, "s1")) {
 
    if (s1) { free(s1); }
 
    s1=strdup(valc);
 
  }
 
  if (!strcmp(namec, "s2")) {
 
    if (s2) { free(s2); }
 
    s2=strdup(valc);
 
  }
 
  if (!strcmp(namec, "s3")) {
 
    if (s3) { free(s3); }
 
    s3=strdup(valc);
 
  }
 
  if (!strcmp(namec, "b1")) {
 
    b1 = strtobool(valc);
 
  }
 
  if (!strcmp(namec, "b2")) {
 
    b2 = strtobool(valc);
 
  }
 
  if (!strcmp(namec, "b3")) {
 
    b3 = strtobool(valc);
 
  }
 
  if (!strcmp(namec, "b4")) {
 
    b4 = strtobool(valc);
 
  }
 
  if (!strcmp(namec, "dir1")) {
 
    if (dir1) { free(dir1); }
 
    dir1=strdup(valc);
 
  }
 
  if (!strcmp(namec, "dir2")) {
 
    if (dir2) { free(dir2); }
 
    dir2=strdup(valc);
 
  }
 
}
 
void Parameter::AssignValArrayToPar(const char *namec, vector<double> valarray) {
 
if (!strcmp(namec, "D")) {
 
  int i=0;
 
  vector<double>::const_iterator v=valarray.begin();
 
  while (v!=valarray.end() && i <= 14 ) {
 
     D[i++]=*(v++);
 
  if (!strcmp(namec, "D")) {
 
    int i=0;
 
    vector<double>::const_iterator v=valarray.begin();
 
    while (v!=valarray.end() && i <= 14 ) {
 
      D[i++]=*(v++);
 
    }
 
  }
 
}
 
if (!strcmp(namec, "initval")) {
 
  int i=0;
 
  vector<double>::const_iterator v=valarray.begin();
 
  while (v!=valarray.end() && i <= 14 ) {
 
     initval[i++]=*(v++);
 
  if (!strcmp(namec, "initval")) {
 
    int i=0;
 
    vector<double>::const_iterator v=valarray.begin();
 
    while (v!=valarray.end() && i <= 14 ) {
 
      initval[i++]=*(v++);
 
    }
 
  }
 
}
 
if (!strcmp(namec, "k")) {
 
  int i=0;
 
  vector<double>::const_iterator v=valarray.begin();
 
  while (v!=valarray.end() && i <= 14 ) {
 
     k[i++]=*(v++);
 
  if (!strcmp(namec, "k")) {
 
    int i=0;
 
    vector<double>::const_iterator v=valarray.begin();
 
    while (v!=valarray.end() && i <= 14 ) {
 
      k[i++]=*(v++);
 
    }
 
  }
 
}
 
}
 

	
 
/* void Parameter::XMLRead(xmlNode *root) {
 
  
 
  xmlNode *cur = root->xmlChildrenNode;
 
  while (cur!=NULL) {
 
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"parameter"))){
 
      xmlNode *par_node = cur->xmlChildrenNode;
 
      while (par_node!=NULL) {
 
	{
 
	  if (!xmlStrcmp(par_node->name, (const xmlChar *)"par")) {
 
	    xmlChar *namec = xmlGetProp(par_node, BAD_CAST "name");
 
	    xmlChar *valc = xmlGetProp(par_node, BAD_CAST "val");
 
	    if (valc) {
 
	      AssignValToPar((const char*)namec,(const char*)valc);
 
	    } else {
 
	      // Probably a valarray
 
	      xmlNode *sub_par_node = par_node->xmlChildrenNode;
 
	      vector<double> valarray; 
 
	      while (sub_par_node != NULL) {
 
		if (!xmlStrcmp(sub_par_node->name, (const xmlChar *)"valarray")) {
 
		  valarray = XMLIO::XMLReadValArray(sub_par_node);
 
		}
 
		sub_par_node = sub_par_node->next;
 
	      }
 
	      AssignValArrayToPar((const char*)namec, valarray);
 
	    }
 
	  }
 
	}	  
 
	par_node = par_node->next;
 
      }
 

	
 
    }
 
    cur=cur->next;
 
  }
 
    
 
}*/
 
   xmlNode *cur = root->xmlChildrenNode;
 
   while (cur!=NULL) {
 
   if ((!xmlStrcmp(cur->name, (const xmlChar *)"parameter"))){
 
   xmlNode *par_node = cur->xmlChildrenNode;
 
   while (par_node!=NULL) {
 
   {
 
   if (!xmlStrcmp(par_node->name, (const xmlChar *)"par")) {
 
   xmlChar *namec = xmlGetProp(par_node, BAD_CAST "name");
 
   xmlChar *valc = xmlGetProp(par_node, BAD_CAST "val");
 
   if (valc) {
 
   AssignValToPar((const char*)namec,(const char*)valc);
 
   } else {
 
   // Probably a valarray
 
   xmlNode *sub_par_node = par_node->xmlChildrenNode;
 
   vector<double> valarray; 
 
   while (sub_par_node != NULL) {
 
   if (!xmlStrcmp(sub_par_node->name, (const xmlChar *)"valarray")) {
 
   valarray = XMLIO::XMLReadValArray(sub_par_node);
 
   }
 
   sub_par_node = sub_par_node->next;
 
   }
 
   AssignValArrayToPar((const char*)namec, valarray);
 
   }
 
   }
 
   }	  
 
   par_node = par_node->next;
 
   }
 

	
 
   }
 
   cur=cur->next;
 
   }
 
   }*/
 

	
 
ostream &operator<<(ostream &os, Parameter &p) {
 
  p.Write(os);
 
  return os;
 
}
 

	
src/parameter.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#ifndef _PARAMETER_H_
 
#define _PARAMETER_H_
 
#include "vector.h"
 
#include <vector>
 

	
 
#include <libxml/parser.h>
 
#include <libxml/tree.h>
 

	
 
class Parameter {
 
  
 

	
 
 public: 
 
  Parameter();
 
  ~Parameter();
 
  void CleanUp(void);
 
  void Read(const char *filename);
 
  void Write(ostream &os) const;
 
  void XMLAdd(xmlNode *root) const;
 
  void XMLRead(xmlNode *root);
 
  void AssignValToPar(const char *namec, const char *valc);
 
  void AssignValArrayToPar(const char *namec, vector<double> valarray);
 
  char * arrowcolor;
 
  double arrowsize;
 
  char * textcolor;
 
  int cellnumsize;
 
  int nodenumsize;
 
  double node_mag;
 
  double outlinewidth;
 
  char * cell_outline_color;
 
  int resize_stride;
 
  double T;
 
  double lambda_length;
 
  double lambda_celllength;
 
  double target_length;
 
  double cell_expansion_rate;
 
  double cell_div_expansion_rate;
 
  bool auxin_dependent_growth;
 
  double ode_accuracy;
 
  double mc_stepsize;
 
  double mc_cell_stepsize;
 
  double energy_threshold;
 
  double bend_lambda;
 
  double alignment_lambda;
 
  double rel_cell_div_threshold;
 
  double rel_perimeter_stiffness;
 
  double collapse_node_threshold;
 
  double morphogen_div_threshold;
 
  double morphogen_expansion_threshold;
 
  bool copy_wall;
 
  double source;
 
  double * D;
 
  double * initval;
 
  double k1;
 
  double k2;
 
  double r;
 
  double kr;
 
  double km;
 
  double Pi_tot;
 
  double transport;
 
  double ka;
 
  double pin_prod;
 
  double pin_prod_in_epidermis;
 
  double pin_breakdown;
 
  double pin_breakdown_internal;
 
  double aux1prod;
 
  double aux1prodmeso;
 
  double aux1decay;
 
  double aux1decaymeso;
 
  double aux1transport;
 
  double aux_cons;
 
  double aux_breakdown;
 
  double kaux1;
 
  double kap;
 
  double leaf_tip_source;
 
  double sam_efflux;
 
  double sam_auxin;
 
  double sam_auxin_breakdown;
 
  double van3prod;
 
  double van3autokat;
 
  double van3sat;
 
  double k2van3;
 
  double dt;
 
  double rd_dt;
 
  char * datadir;
 
  bool movie;
 
  int nit;
 
  double maxt;
 
  int storage_stride;
 
  int xml_storage_stride;
 
  int rseed;
 
  int constituous_expansion_limit;
 
  double vessel_inh_level;
 
  double vessel_expansion_rate;
 
  double d;
 
  double e;
 
  double f;
 
  double c;
 
  double mu;
 
  double nu;
 
  double rho0;
 
  double rho1;
 
  double c0;
 
  double gamma;
 
  double eps;
 
  double * k;
 
  int i1;
 
  int i2;
 
  int i3;
 
  int i4;
 
  int i5;
 
  char * s1;
 
  char * s2;
 
  char * s3;
 
  bool b1;
 
  bool b2;
 
  bool b3;
 
  bool b4;
 
  char * dir1;
 
  char * dir2;
 
 private:
 
};
 

	
 
ostream &operator<<(ostream &os, Parameter &p);
 
const char *sbool(const bool &p);
 

	
 

	
 
#endif
src/pardialog.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include "pardialog.h"
 
#include "parameter.h"
 
#include <cstring>
 
#include <qdialog.h>
 
#include <qlabel.h>
 
#include <qlineedit.h>
 
#include <qmessagebox.h>
 

	
 
static const std::string _module_id("$Id$");
 

	
 
ParameterDialog::ParameterDialog(QWidget *parent, const char *name, Qt::WindowFlags f) : QDialog(parent,name,false,f) {
 
  extern Parameter par;
 
  arrowcolor_edit = new QLineEdit( QString("%1").arg(par.arrowcolor), this, "arrowcolor_edit" );
 
  arrowsize_edit = new QLineEdit( QString("%1").arg(par.arrowsize), this, "arrowsize_edit" );
 
  textcolor_edit = new QLineEdit( QString("%1").arg(par.textcolor), this, "textcolor_edit" );
 
  cellnumsize_edit = new QLineEdit( QString("%1").arg(par.cellnumsize), this, "cellnumsize_edit" );
 
  nodenumsize_edit = new QLineEdit( QString("%1").arg(par.nodenumsize), this, "nodenumsize_edit" );
 
  node_mag_edit = new QLineEdit( QString("%1").arg(par.node_mag), this, "node_mag_edit" );
 
  outlinewidth_edit = new QLineEdit( QString("%1").arg(par.outlinewidth), this, "outlinewidth_edit" );
 
  cell_outline_color_edit = new QLineEdit( QString("%1").arg(par.cell_outline_color), this, "cell_outline_color_edit" );
 
  resize_stride_edit = new QLineEdit( QString("%1").arg(par.resize_stride), this, "resize_stride_edit" );
 
  T_edit = new QLineEdit( QString("%1").arg(par.T), this, "T_edit" );
 
  lambda_length_edit = new QLineEdit( QString("%1").arg(par.lambda_length), this, "lambda_length_edit" );
 
  lambda_celllength_edit = new QLineEdit( QString("%1").arg(par.lambda_celllength), this, "lambda_celllength_edit" );
 
  target_length_edit = new QLineEdit( QString("%1").arg(par.target_length), this, "target_length_edit" );
 
  cell_expansion_rate_edit = new QLineEdit( QString("%1").arg(par.cell_expansion_rate), this, "cell_expansion_rate_edit" );
 
  cell_div_expansion_rate_edit = new QLineEdit( QString("%1").arg(par.cell_div_expansion_rate), this, "cell_div_expansion_rate_edit" );
 
  auxin_dependent_growth_edit = new QLineEdit( QString("%1").arg(sbool(par.auxin_dependent_growth)), this, "auxin_dependent_growth_edit" );
 
  ode_accuracy_edit = new QLineEdit( QString("%1").arg(par.ode_accuracy), this, "ode_accuracy_edit" );
 
  mc_stepsize_edit = new QLineEdit( QString("%1").arg(par.mc_stepsize), this, "mc_stepsize_edit" );
 
  mc_cell_stepsize_edit = new QLineEdit( QString("%1").arg(par.mc_cell_stepsize), this, "mc_cell_stepsize_edit" );
 
  energy_threshold_edit = new QLineEdit( QString("%1").arg(par.energy_threshold), this, "energy_threshold_edit" );
 
  bend_lambda_edit = new QLineEdit( QString("%1").arg(par.bend_lambda), this, "bend_lambda_edit" );
 
  alignment_lambda_edit = new QLineEdit( QString("%1").arg(par.alignment_lambda), this, "alignment_lambda_edit" );
 
  rel_cell_div_threshold_edit = new QLineEdit( QString("%1").arg(par.rel_cell_div_threshold), this, "rel_cell_div_threshold_edit" );
 
  rel_perimeter_stiffness_edit = new QLineEdit( QString("%1").arg(par.rel_perimeter_stiffness), this, "rel_perimeter_stiffness_edit" );
 
  collapse_node_threshold_edit = new QLineEdit( QString("%1").arg(par.collapse_node_threshold), this, "collapse_node_threshold_edit" );
 
  morphogen_div_threshold_edit = new QLineEdit( QString("%1").arg(par.morphogen_div_threshold), this, "morphogen_div_threshold_edit" );
 
  morphogen_expansion_threshold_edit = new QLineEdit( QString("%1").arg(par.morphogen_expansion_threshold), this, "morphogen_expansion_threshold_edit" );
 
  copy_wall_edit = new QLineEdit( QString("%1").arg(sbool(par.copy_wall)), this, "copy_wall_edit" );
 
  source_edit = new QLineEdit( QString("%1").arg(par.source), this, "source_edit" );
 
  QString D_string("%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12,%13,%14,%15");
 
  D_string = D_string.arg(par.D[0]).arg(par.D[1]).arg(par.D[2]).arg(par.D[3]).arg(par.D[4]).arg(par.D[5]).arg(par.D[6]).arg(par.D[7]).arg(par.D[8]).arg(par.D[9]).arg(par.D[10]).arg(par.D[11]).arg(par.D[12]).arg(par.D[13]).arg(par.D[14]);
 
  D_edit = new QLineEdit( D_string, this, "D_edit" );
 
  QString initval_string("%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12,%13,%14,%15");
 
  initval_string = initval_string.arg(par.initval[0]).arg(par.initval[1]).arg(par.initval[2]).arg(par.initval[3]).arg(par.initval[4]).arg(par.initval[5]).arg(par.initval[6]).arg(par.initval[7]).arg(par.initval[8]).arg(par.initval[9]).arg(par.initval[10]).arg(par.initval[11]).arg(par.initval[12]).arg(par.initval[13]).arg(par.initval[14]);
 
  initval_edit = new QLineEdit( initval_string, this, "initval_edit" );
 
  k1_edit = new QLineEdit( QString("%1").arg(par.k1), this, "k1_edit" );
 
  k2_edit = new QLineEdit( QString("%1").arg(par.k2), this, "k2_edit" );
 
  r_edit = new QLineEdit( QString("%1").arg(par.r), this, "r_edit" );
 
  kr_edit = new QLineEdit( QString("%1").arg(par.kr), this, "kr_edit" );
 
  km_edit = new QLineEdit( QString("%1").arg(par.km), this, "km_edit" );
 
  Pi_tot_edit = new QLineEdit( QString("%1").arg(par.Pi_tot), this, "Pi_tot_edit" );
 
  transport_edit = new QLineEdit( QString("%1").arg(par.transport), this, "transport_edit" );
 
  ka_edit = new QLineEdit( QString("%1").arg(par.ka), this, "ka_edit" );
 
  pin_prod_edit = new QLineEdit( QString("%1").arg(par.pin_prod), this, "pin_prod_edit" );
 
  pin_prod_in_epidermis_edit = new QLineEdit( QString("%1").arg(par.pin_prod_in_epidermis), this, "pin_prod_in_epidermis_edit" );
 
  pin_breakdown_edit = new QLineEdit( QString("%1").arg(par.pin_breakdown), this, "pin_breakdown_edit" );
 
  pin_breakdown_internal_edit = new QLineEdit( QString("%1").arg(par.pin_breakdown_internal), this, "pin_breakdown_internal_edit" );
 
  aux1prod_edit = new QLineEdit( QString("%1").arg(par.aux1prod), this, "aux1prod_edit" );
 
  aux1prodmeso_edit = new QLineEdit( QString("%1").arg(par.aux1prodmeso), this, "aux1prodmeso_edit" );
 
  aux1decay_edit = new QLineEdit( QString("%1").arg(par.aux1decay), this, "aux1decay_edit" );
 
  aux1decaymeso_edit = new QLineEdit( QString("%1").arg(par.aux1decaymeso), this, "aux1decaymeso_edit" );
 
  aux1transport_edit = new QLineEdit( QString("%1").arg(par.aux1transport), this, "aux1transport_edit" );
 
  aux_cons_edit = new QLineEdit( QString("%1").arg(par.aux_cons), this, "aux_cons_edit" );
 
  aux_breakdown_edit = new QLineEdit( QString("%1").arg(par.aux_breakdown), this, "aux_breakdown_edit" );
 
  kaux1_edit = new QLineEdit( QString("%1").arg(par.kaux1), this, "kaux1_edit" );
 
  kap_edit = new QLineEdit( QString("%1").arg(par.kap), this, "kap_edit" );
 
  leaf_tip_source_edit = new QLineEdit( QString("%1").arg(par.leaf_tip_source), this, "leaf_tip_source_edit" );
 
  sam_efflux_edit = new QLineEdit( QString("%1").arg(par.sam_efflux), this, "sam_efflux_edit" );
 
  sam_auxin_edit = new QLineEdit( QString("%1").arg(par.sam_auxin), this, "sam_auxin_edit" );
 
  sam_auxin_breakdown_edit = new QLineEdit( QString("%1").arg(par.sam_auxin_breakdown), this, "sam_auxin_breakdown_edit" );
 
  van3prod_edit = new QLineEdit( QString("%1").arg(par.van3prod), this, "van3prod_edit" );
 
  van3autokat_edit = new QLineEdit( QString("%1").arg(par.van3autokat), this, "van3autokat_edit" );
 
  van3sat_edit = new QLineEdit( QString("%1").arg(par.van3sat), this, "van3sat_edit" );
 
  k2van3_edit = new QLineEdit( QString("%1").arg(par.k2van3), this, "k2van3_edit" );
 
  dt_edit = new QLineEdit( QString("%1").arg(par.dt), this, "dt_edit" );
 
  rd_dt_edit = new QLineEdit( QString("%1").arg(par.rd_dt), this, "rd_dt_edit" );
 
  datadir_edit = new QLineEdit( QString("%1").arg(par.datadir), this, "datadir_edit" );
 
  movie_edit = new QLineEdit( QString("%1").arg(sbool(par.movie)), this, "movie_edit" );
 
  nit_edit = new QLineEdit( QString("%1").arg(par.nit), this, "nit_edit" );
 
  maxt_edit = new QLineEdit( QString("%1").arg(par.maxt), this, "maxt_edit" );
 
  storage_stride_edit = new QLineEdit( QString("%1").arg(par.storage_stride), this, "storage_stride_edit" );
 
  xml_storage_stride_edit = new QLineEdit( QString("%1").arg(par.xml_storage_stride), this, "xml_storage_stride_edit" );
 
  rseed_edit = new QLineEdit( QString("%1").arg(par.rseed), this, "rseed_edit" );
 
  constituous_expansion_limit_edit = new QLineEdit( QString("%1").arg(par.constituous_expansion_limit), this, "constituous_expansion_limit_edit" );
 
  vessel_inh_level_edit = new QLineEdit( QString("%1").arg(par.vessel_inh_level), this, "vessel_inh_level_edit" );
 
  vessel_expansion_rate_edit = new QLineEdit( QString("%1").arg(par.vessel_expansion_rate), this, "vessel_expansion_rate_edit" );
 
  d_edit = new QLineEdit( QString("%1").arg(par.d), this, "d_edit" );
 
  e_edit = new QLineEdit( QString("%1").arg(par.e), this, "e_edit" );
 
  f_edit = new QLineEdit( QString("%1").arg(par.f), this, "f_edit" );
 
  c_edit = new QLineEdit( QString("%1").arg(par.c), this, "c_edit" );
 
  mu_edit = new QLineEdit( QString("%1").arg(par.mu), this, "mu_edit" );
 
  nu_edit = new QLineEdit( QString("%1").arg(par.nu), this, "nu_edit" );
 
  rho0_edit = new QLineEdit( QString("%1").arg(par.rho0), this, "rho0_edit" );
 
  rho1_edit = new QLineEdit( QString("%1").arg(par.rho1), this, "rho1_edit" );
 
  c0_edit = new QLineEdit( QString("%1").arg(par.c0), this, "c0_edit" );
 
  gamma_edit = new QLineEdit( QString("%1").arg(par.gamma), this, "gamma_edit" );
 
  eps_edit = new QLineEdit( QString("%1").arg(par.eps), this, "eps_edit" );
 
  QString k_string("%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12,%13,%14,%15");
 
  k_string = k_string.arg(par.k[0]).arg(par.k[1]).arg(par.k[2]).arg(par.k[3]).arg(par.k[4]).arg(par.k[5]).arg(par.k[6]).arg(par.k[7]).arg(par.k[8]).arg(par.k[9]).arg(par.k[10]).arg(par.k[11]).arg(par.k[12]).arg(par.k[13]).arg(par.k[14]);
 
  k_edit = new QLineEdit( k_string, this, "k_edit" );
 
  i1_edit = new QLineEdit( QString("%1").arg(par.i1), this, "i1_edit" );
 
  i2_edit = new QLineEdit( QString("%1").arg(par.i2), this, "i2_edit" );
 
  i3_edit = new QLineEdit( QString("%1").arg(par.i3), this, "i3_edit" );
 
  i4_edit = new QLineEdit( QString("%1").arg(par.i4), this, "i4_edit" );
 
  i5_edit = new QLineEdit( QString("%1").arg(par.i5), this, "i5_edit" );
 
  s1_edit = new QLineEdit( QString("%1").arg(par.s1), this, "s1_edit" );
 
  s2_edit = new QLineEdit( QString("%1").arg(par.s2), this, "s2_edit" );
 
  s3_edit = new QLineEdit( QString("%1").arg(par.s3), this, "s3_edit" );
 
  b1_edit = new QLineEdit( QString("%1").arg(sbool(par.b1)), this, "b1_edit" );
 
  b2_edit = new QLineEdit( QString("%1").arg(sbool(par.b2)), this, "b2_edit" );
 
  b3_edit = new QLineEdit( QString("%1").arg(sbool(par.b3)), this, "b3_edit" );
 
  b4_edit = new QLineEdit( QString("%1").arg(sbool(par.b4)), this, "b4_edit" );
 
  dir1_edit = new QLineEdit( QString("%1").arg(par.dir1), this, "dir1_edit" );
 
  dir2_edit = new QLineEdit( QString("%1").arg(par.dir2), this, "dir2_edit" );
 
  // make a 1x1 grid; it will auto-expand
 
  QGridLayout *grid = new QGridLayout( this, 1, 1 );
 
  
 

	
 
  // add the first four widgets with (row, column) addressing
 
  setWindowTitle( QString( " Parameter values for The Virtual Leaf") );
 
  grid->addWidget( new QLabel( "<h3> Parameter values for The Virtual Leaf</h3>",this), 0, 0, 1, -1, Qt::AlignCenter);
 
  grid->addWidget( new QLabel( "", this), 0+1, 0, 1, -1);
 
  grid->addWidget( new QLabel( " <b>Visualization</b>", this), 3, 0, 1, 2 );
 
  grid->addWidget( new QLabel( "arrowcolor", this ),4, 0 );
 
  grid->addWidget( arrowcolor_edit, 4, 0+1  );
 
  grid->addWidget( new QLabel( "arrowsize", this ),5, 0 );
 
  grid->addWidget( arrowsize_edit, 5, 0+1  );
 
  grid->addWidget( new QLabel( "textcolor", this ),6, 0 );
 
  grid->addWidget( textcolor_edit, 6, 0+1  );
 
  grid->addWidget( new QLabel( "cellnumsize", this ),7, 0 );
 
  grid->addWidget( cellnumsize_edit, 7, 0+1  );
 
  grid->addWidget( new QLabel( "nodenumsize", this ),8, 0 );
 
  grid->addWidget( nodenumsize_edit, 8, 0+1  );
 
  grid->addWidget( new QLabel( "node_mag", this ),9, 0 );
 
  grid->addWidget( node_mag_edit, 9, 0+1  );
 
  grid->addWidget( new QLabel( "outlinewidth", this ),10, 0 );
 
  grid->addWidget( outlinewidth_edit, 10, 0+1  );
 
  grid->addWidget( new QLabel( "cell_outline_color", this ),11, 0 );
 
  grid->addWidget( cell_outline_color_edit, 11, 0+1  );
 
  grid->addWidget( new QLabel( "resize_stride", this ),12, 0 );
 
  grid->addWidget( resize_stride_edit, 12, 0+1  );
 
  grid->addWidget( new QLabel( "", this), 13, 0, 1, 2 );
 
  grid->addWidget( new QLabel( " <b>Cell mechanics</b>", this), 14, 0, 1, 2 );
 
  grid->addWidget( new QLabel( "T", this ),15, 0 );
 
  grid->addWidget( T_edit, 15, 0+1  );
 
  grid->addWidget( new QLabel( "lambda_length", this ),16, 0 );
 
  grid->addWidget( lambda_length_edit, 16, 0+1  );
 
  grid->addWidget( new QLabel( "lambda_celllength", this ),17, 0 );
 
  grid->addWidget( lambda_celllength_edit, 17, 0+1  );
 
  grid->addWidget( new QLabel( "target_length", this ),18, 0 );
 
  grid->addWidget( target_length_edit, 18, 0+1  );
 
  grid->addWidget( new QLabel( "cell_expansion_rate", this ),19, 0 );
 
  grid->addWidget( cell_expansion_rate_edit, 19, 0+1  );
 
  grid->addWidget( new QLabel( "cell_div_expansion_rate", this ),20, 0 );
 
  grid->addWidget( cell_div_expansion_rate_edit, 20, 0+1  );
 
  grid->addWidget( new QLabel( "auxin_dependent_growth", this ),21, 0 );
 
  grid->addWidget( auxin_dependent_growth_edit, 21, 0+1  );
 
  grid->addWidget( new QLabel( "ode_accuracy", this ),22, 0 );
 
  grid->addWidget( ode_accuracy_edit, 22, 0+1  );
 
  grid->addWidget( new QLabel( "mc_stepsize", this ),23, 0 );
 
  grid->addWidget( mc_stepsize_edit, 23, 0+1  );
 
  grid->addWidget( new QLabel( "mc_cell_stepsize", this ),24, 0 );
 
  grid->addWidget( mc_cell_stepsize_edit, 24, 0+1  );
 
  grid->addWidget( new QLabel( "energy_threshold", this ),25, 0 );
 
  grid->addWidget( energy_threshold_edit, 25, 0+1  );
 
  grid->addWidget( new QLabel( "bend_lambda", this ),26, 0 );
 
  grid->addWidget( bend_lambda_edit, 26, 0+1  );
 
  grid->addWidget( new QLabel( "alignment_lambda", this ),27, 0 );
 
  grid->addWidget( alignment_lambda_edit, 27, 0+1  );
 
  grid->addWidget( new QLabel( "rel_cell_div_threshold", this ),28, 0 );
 
  grid->addWidget( rel_cell_div_threshold_edit, 28, 0+1  );
 
  grid->addWidget( new QLabel( "rel_perimeter_stiffness", this ),29, 0 );
 
  grid->addWidget( rel_perimeter_stiffness_edit, 29, 0+1  );
 
  grid->addWidget( new QLabel( "collapse_node_threshold", this ),3, 2 );
 
  grid->addWidget( collapse_node_threshold_edit, 3, 2+1  );
 
  grid->addWidget( new QLabel( "morphogen_div_threshold", this ),4, 2 );
 
  grid->addWidget( morphogen_div_threshold_edit, 4, 2+1  );
 
  grid->addWidget( new QLabel( "morphogen_expansion_threshold", this ),5, 2 );
 
  grid->addWidget( morphogen_expansion_threshold_edit, 5, 2+1  );
 
  grid->addWidget( new QLabel( "copy_wall", this ),6, 2 );
 
  grid->addWidget( copy_wall_edit, 6, 2+1  );
 
  grid->addWidget( new QLabel( "", this), 7, 2, 1, 2 );
 
  grid->addWidget( new QLabel( " <b>Auxin transport and PIN1 dynamics</b>", this), 8, 2, 1, 2 );
 
  grid->addWidget( new QLabel( "source", this ),9, 2 );
 
  grid->addWidget( source_edit, 9, 2+1  );
 
  grid->addWidget( new QLabel( "D", this ),10, 2 );
 
  grid->addWidget( D_edit, 10, 2+1  );
 
  grid->addWidget( new QLabel( "initval", this ),11, 2 );
 
  grid->addWidget( initval_edit, 11, 2+1  );
 
  grid->addWidget( new QLabel( "k1", this ),12, 2 );
 
  grid->addWidget( k1_edit, 12, 2+1  );
 
  grid->addWidget( new QLabel( "k2", this ),13, 2 );
 
  grid->addWidget( k2_edit, 13, 2+1  );
 
  grid->addWidget( new QLabel( "r", this ),14, 2 );
 
  grid->addWidget( r_edit, 14, 2+1  );
 
  grid->addWidget( new QLabel( "kr", this ),15, 2 );
 
  grid->addWidget( kr_edit, 15, 2+1  );
 
  grid->addWidget( new QLabel( "km", this ),16, 2 );
 
  grid->addWidget( km_edit, 16, 2+1  );
 
  grid->addWidget( new QLabel( "Pi_tot", this ),17, 2 );
 
  grid->addWidget( Pi_tot_edit, 17, 2+1  );
 
  grid->addWidget( new QLabel( "transport", this ),18, 2 );
 
  grid->addWidget( transport_edit, 18, 2+1  );
 
  grid->addWidget( new QLabel( "ka", this ),19, 2 );
 
  grid->addWidget( ka_edit, 19, 2+1  );
 
  grid->addWidget( new QLabel( "pin_prod", this ),20, 2 );
 
  grid->addWidget( pin_prod_edit, 20, 2+1  );
 
  grid->addWidget( new QLabel( "pin_prod_in_epidermis", this ),21, 2 );
 
  grid->addWidget( pin_prod_in_epidermis_edit, 21, 2+1  );
 
  grid->addWidget( new QLabel( "pin_breakdown", this ),22, 2 );
 
  grid->addWidget( pin_breakdown_edit, 22, 2+1  );
 
  grid->addWidget( new QLabel( "pin_breakdown_internal", this ),23, 2 );
 
  grid->addWidget( pin_breakdown_internal_edit, 23, 2+1  );
 
  grid->addWidget( new QLabel( "aux1prod", this ),24, 2 );
 
  grid->addWidget( aux1prod_edit, 24, 2+1  );
 
  grid->addWidget( new QLabel( "aux1prodmeso", this ),25, 2 );
 
  grid->addWidget( aux1prodmeso_edit, 25, 2+1  );
 
  grid->addWidget( new QLabel( "aux1decay", this ),26, 2 );
 
  grid->addWidget( aux1decay_edit, 26, 2+1  );
 
  grid->addWidget( new QLabel( "aux1decaymeso", this ),27, 2 );
 
  grid->addWidget( aux1decaymeso_edit, 27, 2+1  );
 
  grid->addWidget( new QLabel( "aux1transport", this ),28, 2 );
 
  grid->addWidget( aux1transport_edit, 28, 2+1  );
 
  grid->addWidget( new QLabel( "aux_cons", this ),29, 2 );
 
  grid->addWidget( aux_cons_edit, 29, 2+1  );
 
  grid->addWidget( new QLabel( "aux_breakdown", this ),3, 4 );
 
  grid->addWidget( aux_breakdown_edit, 3, 4+1  );
 
  grid->addWidget( new QLabel( "kaux1", this ),4, 4 );
 
  grid->addWidget( kaux1_edit, 4, 4+1  );
 
  grid->addWidget( new QLabel( "kap", this ),5, 4 );
 
  grid->addWidget( kap_edit, 5, 4+1  );
 
  grid->addWidget( new QLabel( "leaf_tip_source", this ),6, 4 );
 
  grid->addWidget( leaf_tip_source_edit, 6, 4+1  );
 
  grid->addWidget( new QLabel( "sam_efflux", this ),7, 4 );
 
  grid->addWidget( sam_efflux_edit, 7, 4+1  );
 
  grid->addWidget( new QLabel( "sam_auxin", this ),8, 4 );
 
  grid->addWidget( sam_auxin_edit, 8, 4+1  );
 
  grid->addWidget( new QLabel( "sam_auxin_breakdown", this ),9, 4 );
 
  grid->addWidget( sam_auxin_breakdown_edit, 9, 4+1  );
 
  grid->addWidget( new QLabel( "van3prod", this ),10, 4 );
 
  grid->addWidget( van3prod_edit, 10, 4+1  );
 
  grid->addWidget( new QLabel( "van3autokat", this ),11, 4 );
 
  grid->addWidget( van3autokat_edit, 11, 4+1  );
 
  grid->addWidget( new QLabel( "van3sat", this ),12, 4 );
 
  grid->addWidget( van3sat_edit, 12, 4+1  );
 
  grid->addWidget( new QLabel( "k2van3", this ),13, 4 );
 
  grid->addWidget( k2van3_edit, 13, 4+1  );
 
  grid->addWidget( new QLabel( "", this), 14, 4, 1, 2 );
 
  grid->addWidget( new QLabel( " <b>Integration parameters</b>", this), 15, 4, 1, 2 );
 
  grid->addWidget( new QLabel( "dt", this ),16, 4 );
 
  grid->addWidget( dt_edit, 16, 4+1  );
 
  grid->addWidget( new QLabel( "rd_dt", this ),17, 4 );
 
  grid->addWidget( rd_dt_edit, 17, 4+1  );
 
  grid->addWidget( new QLabel( "datadir", this ),18, 4 );
 
  grid->addWidget( datadir_edit, 18, 4+1  );
 
  grid->addWidget( new QLabel( "movie", this ),19, 4 );
 
  grid->addWidget( movie_edit, 19, 4+1  );
 
  grid->addWidget( new QLabel( "nit", this ),20, 4 );
 
  grid->addWidget( nit_edit, 20, 4+1  );
 
  grid->addWidget( new QLabel( "maxt", this ),21, 4 );
 
  grid->addWidget( maxt_edit, 21, 4+1  );
 
  grid->addWidget( new QLabel( "storage_stride", this ),22, 4 );
 
  grid->addWidget( storage_stride_edit, 22, 4+1  );
 
  grid->addWidget( new QLabel( "xml_storage_stride", this ),23, 4 );
 
  grid->addWidget( xml_storage_stride_edit, 23, 4+1  );
 
  grid->addWidget( new QLabel( "rseed", this ),24, 4 );
 
  grid->addWidget( rseed_edit, 24, 4+1  );
 
  grid->addWidget( new QLabel( "", this), 25, 4, 1, 2 );
 
  grid->addWidget( new QLabel( " <b>Meinhardt leaf venation model</b>", this), 26, 4, 1, 2 );
 
  grid->addWidget( new QLabel( "constituous_expansion_limit", this ),27, 4 );
 
  grid->addWidget( constituous_expansion_limit_edit, 27, 4+1  );
 
  grid->addWidget( new QLabel( "vessel_inh_level", this ),28, 4 );
 
  grid->addWidget( vessel_inh_level_edit, 28, 4+1  );
 
  grid->addWidget( new QLabel( "vessel_expansion_rate", this ),29, 4 );
 
  grid->addWidget( vessel_expansion_rate_edit, 29, 4+1  );
 
  grid->addWidget( new QLabel( "d", this ),3, 6 );
 
  grid->addWidget( d_edit, 3, 6+1  );
 
  grid->addWidget( new QLabel( "e", this ),4, 6 );
 
  grid->addWidget( e_edit, 4, 6+1  );
 
  grid->addWidget( new QLabel( "f", this ),5, 6 );
 
  grid->addWidget( f_edit, 5, 6+1  );
 
  grid->addWidget( new QLabel( "c", this ),6, 6 );
 
  grid->addWidget( c_edit, 6, 6+1  );
 
  grid->addWidget( new QLabel( "mu", this ),7, 6 );
 
  grid->addWidget( mu_edit, 7, 6+1  );
 
  grid->addWidget( new QLabel( "nu", this ),8, 6 );
 
  grid->addWidget( nu_edit, 8, 6+1  );
 
  grid->addWidget( new QLabel( "rho0", this ),9, 6 );
 
  grid->addWidget( rho0_edit, 9, 6+1  );
 
  grid->addWidget( new QLabel( "rho1", this ),10, 6 );
 
  grid->addWidget( rho1_edit, 10, 6+1  );
 
  grid->addWidget( new QLabel( "c0", this ),11, 6 );
 
  grid->addWidget( c0_edit, 11, 6+1  );
 
  grid->addWidget( new QLabel( "gamma", this ),12, 6 );
 
  grid->addWidget( gamma_edit, 12, 6+1  );
 
  grid->addWidget( new QLabel( "eps", this ),13, 6 );
 
  grid->addWidget( eps_edit, 13, 6+1  );
 
  grid->addWidget( new QLabel( "", this), 14, 6, 1, 2 );
 
  grid->addWidget( new QLabel( " <b>User-defined parameters</b>", this), 15, 6, 1, 2 );
 
  grid->addWidget( new QLabel( "k", this ),16, 6 );
 
  grid->addWidget( k_edit, 16, 6+1  );
 
  grid->addWidget( new QLabel( "i1", this ),17, 6 );
 
  grid->addWidget( i1_edit, 17, 6+1  );
 
  grid->addWidget( new QLabel( "i2", this ),18, 6 );
 
  grid->addWidget( i2_edit, 18, 6+1  );
 
  grid->addWidget( new QLabel( "i3", this ),19, 6 );
 
  grid->addWidget( i3_edit, 19, 6+1  );
 
  grid->addWidget( new QLabel( "i4", this ),20, 6 );
 
  grid->addWidget( i4_edit, 20, 6+1  );
 
  grid->addWidget( new QLabel( "i5", this ),21, 6 );
 
  grid->addWidget( i5_edit, 21, 6+1  );
 
  grid->addWidget( new QLabel( "s1", this ),22, 6 );
 
  grid->addWidget( s1_edit, 22, 6+1  );
 
  grid->addWidget( new QLabel( "s2", this ),23, 6 );
 
  grid->addWidget( s2_edit, 23, 6+1  );
 
  grid->addWidget( new QLabel( "s3", this ),24, 6 );
 
  grid->addWidget( s3_edit, 24, 6+1  );
 
  grid->addWidget( new QLabel( "b1", this ),25, 6 );
 
  grid->addWidget( b1_edit, 25, 6+1  );
 
  grid->addWidget( new QLabel( "b2", this ),26, 6 );
 
  grid->addWidget( b2_edit, 26, 6+1  );
 
  grid->addWidget( new QLabel( "b3", this ),27, 6 );
 
  grid->addWidget( b3_edit, 27, 6+1  );
 
  grid->addWidget( new QLabel( "b4", this ),28, 6 );
 
  grid->addWidget( b4_edit, 28, 6+1  );
 
  grid->addWidget( new QLabel( "dir1", this ),29, 6 );
 
  grid->addWidget( dir1_edit, 29, 6+1  );
 
  grid->addWidget( new QLabel( "dir2", this ),3, 8 );
 
  grid->addWidget( dir2_edit, 3, 8+1  );
 
  QPushButton *pb = new QPushButton( "&Write", this );
 
  grid->addWidget(pb, 31, 6 );
 
  connect( pb, SIGNAL( clicked() ), this, SLOT( write() ) );
 
  QPushButton *pb2 = new QPushButton( "&Close", this );
 
  grid->addWidget(pb2,31, 6+1 );
 
  connect( pb2, SIGNAL( clicked() ), this, SLOT( close() ) );
 
  QPushButton *pb3 = new QPushButton( "&Reset", this );
 
  grid->addWidget(pb3, 31, 6+2 );
 
  connect( pb3, SIGNAL( clicked() ), this, SLOT( Reset() ) );
 
  show();
 
};
 

	
 
ParameterDialog::~ParameterDialog(void) {
 
delete arrowcolor_edit;
 
delete arrowsize_edit;
 
delete textcolor_edit;
 
delete cellnumsize_edit;
 
delete nodenumsize_edit;
 
delete node_mag_edit;
 
delete outlinewidth_edit;
 
delete cell_outline_color_edit;
 
delete resize_stride_edit;
 
delete T_edit;
 
delete lambda_length_edit;
 
delete lambda_celllength_edit;
 
delete target_length_edit;
 
delete cell_expansion_rate_edit;
 
delete cell_div_expansion_rate_edit;
 
delete auxin_dependent_growth_edit;
 
delete ode_accuracy_edit;
 
delete mc_stepsize_edit;
 
delete mc_cell_stepsize_edit;
 
delete energy_threshold_edit;
 
delete bend_lambda_edit;
 
delete alignment_lambda_edit;
 
delete rel_cell_div_threshold_edit;
 
delete rel_perimeter_stiffness_edit;
 
delete collapse_node_threshold_edit;
 
delete morphogen_div_threshold_edit;
 
delete morphogen_expansion_threshold_edit;
 
delete copy_wall_edit;
 
delete source_edit;
 
delete D_edit;
 
delete initval_edit;
 
delete k1_edit;
 
delete k2_edit;
 
delete r_edit;
 
delete kr_edit;
 
delete km_edit;
 
delete Pi_tot_edit;
 
delete transport_edit;
 
delete ka_edit;
 
delete pin_prod_edit;
 
delete pin_prod_in_epidermis_edit;
 
delete pin_breakdown_edit;
 
delete pin_breakdown_internal_edit;
 
delete aux1prod_edit;
 
delete aux1prodmeso_edit;
 
delete aux1decay_edit;
 
delete aux1decaymeso_edit;
 
delete aux1transport_edit;
 
delete aux_cons_edit;
 
delete aux_breakdown_edit;
 
delete kaux1_edit;
 
delete kap_edit;
 
delete leaf_tip_source_edit;
 
delete sam_efflux_edit;
 
delete sam_auxin_edit;
 
delete sam_auxin_breakdown_edit;
 
delete van3prod_edit;
 
delete van3autokat_edit;
 
delete van3sat_edit;
 
delete k2van3_edit;
 
delete dt_edit;
 
delete rd_dt_edit;
 
delete datadir_edit;
 
delete movie_edit;
 
delete nit_edit;
 
delete maxt_edit;
 
delete storage_stride_edit;
 
delete xml_storage_stride_edit;
 
delete rseed_edit;
 
delete constituous_expansion_limit_edit;
 
delete vessel_inh_level_edit;
 
delete vessel_expansion_rate_edit;
 
delete d_edit;
 
delete e_edit;
 
delete f_edit;
 
delete c_edit;
 
delete mu_edit;
 
delete nu_edit;
 
delete rho0_edit;
 
delete rho1_edit;
 
delete c0_edit;
 
delete gamma_edit;
 
delete eps_edit;
 
delete k_edit;
 
delete i1_edit;
 
delete i2_edit;
 
delete i3_edit;
 
delete i4_edit;
 
delete i5_edit;
 
delete s1_edit;
 
delete s2_edit;
 
delete s3_edit;
 
delete b1_edit;
 
delete b2_edit;
 
delete b3_edit;
 
delete b4_edit;
 
delete dir1_edit;
 
delete dir2_edit;
 
  delete arrowcolor_edit;
 
  delete arrowsize_edit;
 
  delete textcolor_edit;
 
  delete cellnumsize_edit;
 
  delete nodenumsize_edit;
 
  delete node_mag_edit;
 
  delete outlinewidth_edit;
 
  delete cell_outline_color_edit;
 
  delete resize_stride_edit;
 
  delete T_edit;
 
  delete lambda_length_edit;
 
  delete lambda_celllength_edit;
 
  delete target_length_edit;
 
  delete cell_expansion_rate_edit;
 
  delete cell_div_expansion_rate_edit;
 
  delete auxin_dependent_growth_edit;
 
  delete ode_accuracy_edit;
 
  delete mc_stepsize_edit;
 
  delete mc_cell_stepsize_edit;
 
  delete energy_threshold_edit;
 
  delete bend_lambda_edit;
 
  delete alignment_lambda_edit;
 
  delete rel_cell_div_threshold_edit;
 
  delete rel_perimeter_stiffness_edit;
 
  delete collapse_node_threshold_edit;
 
  delete morphogen_div_threshold_edit;
 
  delete morphogen_expansion_threshold_edit;
 
  delete copy_wall_edit;
 
  delete source_edit;
 
  delete D_edit;
 
  delete initval_edit;
 
  delete k1_edit;
 
  delete k2_edit;
 
  delete r_edit;
 
  delete kr_edit;
 
  delete km_edit;
 
  delete Pi_tot_edit;
 
  delete transport_edit;
 
  delete ka_edit;
 
  delete pin_prod_edit;
 
  delete pin_prod_in_epidermis_edit;
 
  delete pin_breakdown_edit;
 
  delete pin_breakdown_internal_edit;
 
  delete aux1prod_edit;
 
  delete aux1prodmeso_edit;
 
  delete aux1decay_edit;
 
  delete aux1decaymeso_edit;
 
  delete aux1transport_edit;
 
  delete aux_cons_edit;
 
  delete aux_breakdown_edit;
 
  delete kaux1_edit;
 
  delete kap_edit;
 
  delete leaf_tip_source_edit;
 
  delete sam_efflux_edit;
 
  delete sam_auxin_edit;
 
  delete sam_auxin_breakdown_edit;
 
  delete van3prod_edit;
 
  delete van3autokat_edit;
 
  delete van3sat_edit;
 
  delete k2van3_edit;
 
  delete dt_edit;
 
  delete rd_dt_edit;
 
  delete datadir_edit;
 
  delete movie_edit;
 
  delete nit_edit;
 
  delete maxt_edit;
 
  delete storage_stride_edit;
 
  delete xml_storage_stride_edit;
 
  delete rseed_edit;
 
  delete constituous_expansion_limit_edit;
 
  delete vessel_inh_level_edit;
 
  delete vessel_expansion_rate_edit;
 
  delete d_edit;
 
  delete e_edit;
 
  delete f_edit;
 
  delete c_edit;
 
  delete mu_edit;
 
  delete nu_edit;
 
  delete rho0_edit;
 
  delete rho1_edit;
 
  delete c0_edit;
 
  delete gamma_edit;
 
  delete eps_edit;
 
  delete k_edit;
 
  delete i1_edit;
 
  delete i2_edit;
 
  delete i3_edit;
 
  delete i4_edit;
 
  delete i5_edit;
 
  delete s1_edit;
 
  delete s2_edit;
 
  delete s3_edit;
 
  delete b1_edit;
 
  delete b2_edit;
 
  delete b3_edit;
 
  delete b4_edit;
 
  delete dir1_edit;
 
  delete dir2_edit;
 
}
 

	
 
void ParameterDialog::write(void) {
 
  
 

	
 
  extern Parameter par;
 
  QString tmpval;
 
  par.arrowcolor = strdup((const char *)arrowcolor_edit->text());
 
  par.arrowsize = arrowsize_edit->text().toDouble();
 
  par.textcolor = strdup((const char *)textcolor_edit->text());
 
  par.cellnumsize = cellnumsize_edit->text().toInt();
 
  par.nodenumsize = nodenumsize_edit->text().toInt();
 
  par.node_mag = node_mag_edit->text().toDouble();
 
  par.outlinewidth = outlinewidth_edit->text().toDouble();
 
  par.cell_outline_color = strdup((const char *)cell_outline_color_edit->text());
 
  par.resize_stride = resize_stride_edit->text().toInt();
 
  par.T = T_edit->text().toDouble();
 
  par.lambda_length = lambda_length_edit->text().toDouble();
 
  par.lambda_celllength = lambda_celllength_edit->text().toDouble();
 
  par.target_length = target_length_edit->text().toDouble();
 
  par.cell_expansion_rate = cell_expansion_rate_edit->text().toDouble();
 
  par.cell_div_expansion_rate = cell_div_expansion_rate_edit->text().toDouble();
 
  tmpval = auxin_dependent_growth_edit->text().stripWhiteSpace();
 
  if (tmpval == "true" || tmpval == "yes" ) par.auxin_dependent_growth = true;
 
  else if (tmpval == "false" || tmpval == "no") par.auxin_dependent_growth = false;
 
  else {
 
    if (QMessageBox::question(this, "Syntax error", tr("Value %1 of parameter %2 is not recognized as Boolean.\nDo you mean TRUE or FALSE?").arg(tmpval).arg("auxin_dependent_growth"),"True","False", QString::null, 0, 1)==0) par.auxin_dependent_growth=true;
 
      else par.auxin_dependent_growth=false;
 
    else par.auxin_dependent_growth=false;
 
  }
 
  par.ode_accuracy = ode_accuracy_edit->text().toDouble();
 
  par.mc_stepsize = mc_stepsize_edit->text().toDouble();
 
  par.mc_cell_stepsize = mc_cell_stepsize_edit->text().toDouble();
 
  par.energy_threshold = energy_threshold_edit->text().toDouble();
 
  par.bend_lambda = bend_lambda_edit->text().toDouble();
 
  par.alignment_lambda = alignment_lambda_edit->text().toDouble();
 
  par.rel_cell_div_threshold = rel_cell_div_threshold_edit->text().toDouble();
 
  par.rel_perimeter_stiffness = rel_perimeter_stiffness_edit->text().toDouble();
 
  par.collapse_node_threshold = collapse_node_threshold_edit->text().toDouble();
 
  par.morphogen_div_threshold = morphogen_div_threshold_edit->text().toDouble();
 
  par.morphogen_expansion_threshold = morphogen_expansion_threshold_edit->text().toDouble();
 
  tmpval = copy_wall_edit->text().stripWhiteSpace();
 
  if (tmpval == "true" || tmpval == "yes" ) par.copy_wall = true;
 
  else if (tmpval == "false" || tmpval == "no") par.copy_wall = false;
 
  else {
 
    if (QMessageBox::question(this, "Syntax error", tr("Value %1 of parameter %2 is not recognized as Boolean.\nDo you mean TRUE or FALSE?").arg(tmpval).arg("copy_wall"),"True","False", QString::null, 0, 1)==0) par.copy_wall=true;
 
      else par.copy_wall=false;
 
    else par.copy_wall=false;
 
  }
 
  par.source = source_edit->text().toDouble();
 
  tmpval = D_edit->text().section(',', 0, 0);
 
  par.D[0] = tmpval.toDouble();
 
  tmpval = D_edit->text().section(',', 1, 1);
 
  par.D[1] = tmpval.toDouble();
 
  tmpval = D_edit->text().section(',', 2, 2);
 
  par.D[2] = tmpval.toDouble();
 
  tmpval = D_edit->text().section(',', 3, 3);
 
  par.D[3] = tmpval.toDouble();
 
  tmpval = D_edit->text().section(',', 4, 4);
 
  par.D[4] = tmpval.toDouble();
 
  tmpval = D_edit->text().section(',', 5, 5);
 
  par.D[5] = tmpval.toDouble();
 
  tmpval = D_edit->text().section(',', 6, 6);
 
  par.D[6] = tmpval.toDouble();
 
  tmpval = D_edit->text().section(',', 7, 7);
 
  par.D[7] = tmpval.toDouble();
 
  tmpval = D_edit->text().section(',', 8, 8);
 
  par.D[8] = tmpval.toDouble();
 
  tmpval = D_edit->text().section(',', 9, 9);
 
  par.D[9] = tmpval.toDouble();
 
  tmpval = D_edit->text().section(',', 10, 10);
 
  par.D[10] = tmpval.toDouble();
 
  tmpval = D_edit->text().section(',', 11, 11);
 
  par.D[11] = tmpval.toDouble();
 
  tmpval = D_edit->text().section(',', 12, 12);
 
  par.D[12] = tmpval.toDouble();
 
  tmpval = D_edit->text().section(',', 13, 13);
 
  par.D[13] = tmpval.toDouble();
 
  tmpval = D_edit->text().section(',', 14, 14);
 
  par.D[14] = tmpval.toDouble();
 
  tmpval = initval_edit->text().section(',', 0, 0);
 
  par.initval[0] = tmpval.toDouble();
 
  tmpval = initval_edit->text().section(',', 1, 1);
 
  par.initval[1] = tmpval.toDouble();
 
  tmpval = initval_edit->text().section(',', 2, 2);
 
  par.initval[2] = tmpval.toDouble();
 
  tmpval = initval_edit->text().section(',', 3, 3);
 
  par.initval[3] = tmpval.toDouble();
 
  tmpval = initval_edit->text().section(',', 4, 4);
 
  par.initval[4] = tmpval.toDouble();
 
  tmpval = initval_edit->text().section(',', 5, 5);
 
  par.initval[5] = tmpval.toDouble();
 
  tmpval = initval_edit->text().section(',', 6, 6);
 
  par.initval[6] = tmpval.toDouble();
 
  tmpval = initval_edit->text().section(',', 7, 7);
 
  par.initval[7] = tmpval.toDouble();
 
  tmpval = initval_edit->text().section(',', 8, 8);
 
  par.initval[8] = tmpval.toDouble();
 
  tmpval = initval_edit->text().section(',', 9, 9);
 
  par.initval[9] = tmpval.toDouble();
 
  tmpval = initval_edit->text().section(',', 10, 10);
 
  par.initval[10] = tmpval.toDouble();
 
  tmpval = initval_edit->text().section(',', 11, 11);
 
  par.initval[11] = tmpval.toDouble();
 
  tmpval = initval_edit->text().section(',', 12, 12);
 
  par.initval[12] = tmpval.toDouble();
 
  tmpval = initval_edit->text().section(',', 13, 13);
 
  par.initval[13] = tmpval.toDouble();
 
  tmpval = initval_edit->text().section(',', 14, 14);
 
  par.initval[14] = tmpval.toDouble();
 
  par.k1 = k1_edit->text().toDouble();
 
  par.k2 = k2_edit->text().toDouble();
 
  par.r = r_edit->text().toDouble();
 
  par.kr = kr_edit->text().toDouble();
 
  par.km = km_edit->text().toDouble();
 
  par.Pi_tot = Pi_tot_edit->text().toDouble();
 
  par.transport = transport_edit->text().toDouble();
 
  par.ka = ka_edit->text().toDouble();
 
  par.pin_prod = pin_prod_edit->text().toDouble();
 
  par.pin_prod_in_epidermis = pin_prod_in_epidermis_edit->text().toDouble();
 
  par.pin_breakdown = pin_breakdown_edit->text().toDouble();
 
  par.pin_breakdown_internal = pin_breakdown_internal_edit->text().toDouble();
 
  par.aux1prod = aux1prod_edit->text().toDouble();
 
  par.aux1prodmeso = aux1prodmeso_edit->text().toDouble();
 
  par.aux1decay = aux1decay_edit->text().toDouble();
 
  par.aux1decaymeso = aux1decaymeso_edit->text().toDouble();
 
  par.aux1transport = aux1transport_edit->text().toDouble();
 
  par.aux_cons = aux_cons_edit->text().toDouble();
 
  par.aux_breakdown = aux_breakdown_edit->text().toDouble();
 
  par.kaux1 = kaux1_edit->text().toDouble();
 
  par.kap = kap_edit->text().toDouble();
 
  par.leaf_tip_source = leaf_tip_source_edit->text().toDouble();
 
  par.sam_efflux = sam_efflux_edit->text().toDouble();
 
  par.sam_auxin = sam_auxin_edit->text().toDouble();
 
  par.sam_auxin_breakdown = sam_auxin_breakdown_edit->text().toDouble();
 
  par.van3prod = van3prod_edit->text().toDouble();
 
  par.van3autokat = van3autokat_edit->text().toDouble();
 
  par.van3sat = van3sat_edit->text().toDouble();
 
  par.k2van3 = k2van3_edit->text().toDouble();
 
  par.dt = dt_edit->text().toDouble();
 
  par.rd_dt = rd_dt_edit->text().toDouble();
 
  par.datadir = strdup((const char *)datadir_edit->text());
 
  tmpval = movie_edit->text().stripWhiteSpace();
 
  if (tmpval == "true" || tmpval == "yes" ) par.movie = true;
 
  else if (tmpval == "false" || tmpval == "no") par.movie = false;
 
  else {
 
    if (QMessageBox::question(this, "Syntax error", tr("Value %1 of parameter %2 is not recognized as Boolean.\nDo you mean TRUE or FALSE?").arg(tmpval).arg("movie"),"True","False", QString::null, 0, 1)==0) par.movie=true;
 
      else par.movie=false;
 
    else par.movie=false;
 
  }
 
  par.nit = nit_edit->text().toInt();
 
  par.maxt = maxt_edit->text().toDouble();
 
  par.storage_stride = storage_stride_edit->text().toInt();
 
  par.xml_storage_stride = xml_storage_stride_edit->text().toInt();
 
  par.rseed = rseed_edit->text().toInt();
 
  par.constituous_expansion_limit = constituous_expansion_limit_edit->text().toInt();
 
  par.vessel_inh_level = vessel_inh_level_edit->text().toDouble();
 
  par.vessel_expansion_rate = vessel_expansion_rate_edit->text().toDouble();
 
  par.d = d_edit->text().toDouble();
 
  par.e = e_edit->text().toDouble();
 
  par.f = f_edit->text().toDouble();
 
  par.c = c_edit->text().toDouble();
 
  par.mu = mu_edit->text().toDouble();
 
  par.nu = nu_edit->text().toDouble();
 
  par.rho0 = rho0_edit->text().toDouble();
 
  par.rho1 = rho1_edit->text().toDouble();
 
  par.c0 = c0_edit->text().toDouble();
 
  par.gamma = gamma_edit->text().toDouble();
 
  par.eps = eps_edit->text().toDouble();
 
  tmpval = k_edit->text().section(',', 0, 0);
 
  par.k[0] = tmpval.toDouble();
 
  tmpval = k_edit->text().section(',', 1, 1);
 
  par.k[1] = tmpval.toDouble();
 
  tmpval = k_edit->text().section(',', 2, 2);
 
  par.k[2] = tmpval.toDouble();
 
  tmpval = k_edit->text().section(',', 3, 3);
 
  par.k[3] = tmpval.toDouble();
 
  tmpval = k_edit->text().section(',', 4, 4);
 
  par.k[4] = tmpval.toDouble();
 
  tmpval = k_edit->text().section(',', 5, 5);
 
  par.k[5] = tmpval.toDouble();
 
  tmpval = k_edit->text().section(',', 6, 6);
 
  par.k[6] = tmpval.toDouble();
 
  tmpval = k_edit->text().section(',', 7, 7);
 
  par.k[7] = tmpval.toDouble();
 
  tmpval = k_edit->text().section(',', 8, 8);
 
  par.k[8] = tmpval.toDouble();
 
  tmpval = k_edit->text().section(',', 9, 9);
 
  par.k[9] = tmpval.toDouble();
 
  tmpval = k_edit->text().section(',', 10, 10);
 
  par.k[10] = tmpval.toDouble();
 
  tmpval = k_edit->text().section(',', 11, 11);
 
  par.k[11] = tmpval.toDouble();
 
  tmpval = k_edit->text().section(',', 12, 12);
 
  par.k[12] = tmpval.toDouble();
 
  tmpval = k_edit->text().section(',', 13, 13);
 
  par.k[13] = tmpval.toDouble();
 
  tmpval = k_edit->text().section(',', 14, 14);
 
  par.k[14] = tmpval.toDouble();
 
  par.i1 = i1_edit->text().toInt();
 
  par.i2 = i2_edit->text().toInt();
 
  par.i3 = i3_edit->text().toInt();
 
  par.i4 = i4_edit->text().toInt();
 
  par.i5 = i5_edit->text().toInt();
 
  par.s1 = strdup((const char *)s1_edit->text());
 
  par.s2 = strdup((const char *)s2_edit->text());
 
  par.s3 = strdup((const char *)s3_edit->text());
 
  tmpval = b1_edit->text().stripWhiteSpace();
 
  if (tmpval == "true" || tmpval == "yes" ) par.b1 = true;
 
  else if (tmpval == "false" || tmpval == "no") par.b1 = false;
 
  else {
 
    if (QMessageBox::question(this, "Syntax error", tr("Value %1 of parameter %2 is not recognized as Boolean.\nDo you mean TRUE or FALSE?").arg(tmpval).arg("b1"),"True","False", QString::null, 0, 1)==0) par.b1=true;
 
      else par.b1=false;
 
    else par.b1=false;
 
  }
 
  tmpval = b2_edit->text().stripWhiteSpace();
 
  if (tmpval == "true" || tmpval == "yes" ) par.b2 = true;
 
  else if (tmpval == "false" || tmpval == "no") par.b2 = false;
 
  else {
 
    if (QMessageBox::question(this, "Syntax error", tr("Value %1 of parameter %2 is not recognized as Boolean.\nDo you mean TRUE or FALSE?").arg(tmpval).arg("b2"),"True","False", QString::null, 0, 1)==0) par.b2=true;
 
      else par.b2=false;
 
    else par.b2=false;
 
  }
 
  tmpval = b3_edit->text().stripWhiteSpace();
 
  if (tmpval == "true" || tmpval == "yes" ) par.b3 = true;
 
  else if (tmpval == "false" || tmpval == "no") par.b3 = false;
 
  else {
 
    if (QMessageBox::question(this, "Syntax error", tr("Value %1 of parameter %2 is not recognized as Boolean.\nDo you mean TRUE or FALSE?").arg(tmpval).arg("b3"),"True","False", QString::null, 0, 1)==0) par.b3=true;
 
      else par.b3=false;
 
    else par.b3=false;
 
  }
 
  tmpval = b4_edit->text().stripWhiteSpace();
 
  if (tmpval == "true" || tmpval == "yes" ) par.b4 = true;
 
  else if (tmpval == "false" || tmpval == "no") par.b4 = false;
 
  else {
 
    if (QMessageBox::question(this, "Syntax error", tr("Value %1 of parameter %2 is not recognized as Boolean.\nDo you mean TRUE or FALSE?").arg(tmpval).arg("b4"),"True","False", QString::null, 0, 1)==0) par.b4=true;
 
      else par.b4=false;
 
    else par.b4=false;
 
  }
 
  par.dir1 = strdup((const char *)dir1_edit->text());
 
  par.dir2 = strdup((const char *)dir2_edit->text());
 
  Reset();
 

	
 
}
 
void ParameterDialog::Reset(void) {
 
  extern Parameter par;
 
  arrowcolor_edit->setText( QString("%1").arg(par.arrowcolor) );
 
  arrowsize_edit->setText( QString("%1").arg(par.arrowsize) );
 
  textcolor_edit->setText( QString("%1").arg(par.textcolor) );
 
  cellnumsize_edit->setText( QString("%1").arg(par.cellnumsize) );
 
  nodenumsize_edit->setText( QString("%1").arg(par.nodenumsize) );
 
  node_mag_edit->setText( QString("%1").arg(par.node_mag) );
 
  outlinewidth_edit->setText( QString("%1").arg(par.outlinewidth) );
 
  cell_outline_color_edit->setText( QString("%1").arg(par.cell_outline_color) );
 
  resize_stride_edit->setText( QString("%1").arg(par.resize_stride) );
 
  T_edit->setText( QString("%1").arg(par.T) );
 
  lambda_length_edit->setText( QString("%1").arg(par.lambda_length) );
 
  lambda_celllength_edit->setText( QString("%1").arg(par.lambda_celllength) );
 
  target_length_edit->setText( QString("%1").arg(par.target_length) );
 
  cell_expansion_rate_edit->setText( QString("%1").arg(par.cell_expansion_rate) );
 
  cell_div_expansion_rate_edit->setText( QString("%1").arg(par.cell_div_expansion_rate) );
 
  auxin_dependent_growth_edit->setText( QString("%1").arg(sbool(par.auxin_dependent_growth)));
 
  ode_accuracy_edit->setText( QString("%1").arg(par.ode_accuracy) );
 
  mc_stepsize_edit->setText( QString("%1").arg(par.mc_stepsize) );
 
  mc_cell_stepsize_edit->setText( QString("%1").arg(par.mc_cell_stepsize) );
 
  energy_threshold_edit->setText( QString("%1").arg(par.energy_threshold) );
 
  bend_lambda_edit->setText( QString("%1").arg(par.bend_lambda) );
 
  alignment_lambda_edit->setText( QString("%1").arg(par.alignment_lambda) );
 
  rel_cell_div_threshold_edit->setText( QString("%1").arg(par.rel_cell_div_threshold) );
 
  rel_perimeter_stiffness_edit->setText( QString("%1").arg(par.rel_perimeter_stiffness) );
 
  collapse_node_threshold_edit->setText( QString("%1").arg(par.collapse_node_threshold) );
 
  morphogen_div_threshold_edit->setText( QString("%1").arg(par.morphogen_div_threshold) );
 
  morphogen_expansion_threshold_edit->setText( QString("%1").arg(par.morphogen_expansion_threshold) );
 
  copy_wall_edit->setText( QString("%1").arg(sbool(par.copy_wall)));
 
  source_edit->setText( QString("%1").arg(par.source) );
 
  QString D_string("%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12,%13,%14,%15");
 
  D_string = D_string.arg(par.D[0]).arg(par.D[1]).arg(par.D[2]).arg(par.D[3]).arg(par.D[4]).arg(par.D[5]).arg(par.D[6]).arg(par.D[7]).arg(par.D[8]).arg(par.D[9]).arg(par.D[10]).arg(par.D[11]).arg(par.D[12]).arg(par.D[13]).arg(par.D[14]);
 
  D_edit->setText( D_string );
 
  QString initval_string("%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12,%13,%14,%15");
 
  initval_string = initval_string.arg(par.initval[0]).arg(par.initval[1]).arg(par.initval[2]).arg(par.initval[3]).arg(par.initval[4]).arg(par.initval[5]).arg(par.initval[6]).arg(par.initval[7]).arg(par.initval[8]).arg(par.initval[9]).arg(par.initval[10]).arg(par.initval[11]).arg(par.initval[12]).arg(par.initval[13]).arg(par.initval[14]);
 
  initval_edit->setText( initval_string );
 
  k1_edit->setText( QString("%1").arg(par.k1) );
 
  k2_edit->setText( QString("%1").arg(par.k2) );
 
  r_edit->setText( QString("%1").arg(par.r) );
 
  kr_edit->setText( QString("%1").arg(par.kr) );
 
  km_edit->setText( QString("%1").arg(par.km) );
 
  Pi_tot_edit->setText( QString("%1").arg(par.Pi_tot) );
 
  transport_edit->setText( QString("%1").arg(par.transport) );
 
  ka_edit->setText( QString("%1").arg(par.ka) );
 
  pin_prod_edit->setText( QString("%1").arg(par.pin_prod) );
 
  pin_prod_in_epidermis_edit->setText( QString("%1").arg(par.pin_prod_in_epidermis) );
 
  pin_breakdown_edit->setText( QString("%1").arg(par.pin_breakdown) );
 
  pin_breakdown_internal_edit->setText( QString("%1").arg(par.pin_breakdown_internal) );
 
  aux1prod_edit->setText( QString("%1").arg(par.aux1prod) );
 
  aux1prodmeso_edit->setText( QString("%1").arg(par.aux1prodmeso) );
 
  aux1decay_edit->setText( QString("%1").arg(par.aux1decay) );
 
  aux1decaymeso_edit->setText( QString("%1").arg(par.aux1decaymeso) );
 
  aux1transport_edit->setText( QString("%1").arg(par.aux1transport) );
 
  aux_cons_edit->setText( QString("%1").arg(par.aux_cons) );
 
  aux_breakdown_edit->setText( QString("%1").arg(par.aux_breakdown) );
 
  kaux1_edit->setText( QString("%1").arg(par.kaux1) );
 
  kap_edit->setText( QString("%1").arg(par.kap) );
 
  leaf_tip_source_edit->setText( QString("%1").arg(par.leaf_tip_source) );
 
  sam_efflux_edit->setText( QString("%1").arg(par.sam_efflux) );
 
  sam_auxin_edit->setText( QString("%1").arg(par.sam_auxin) );
 
  sam_auxin_breakdown_edit->setText( QString("%1").arg(par.sam_auxin_breakdown) );
 
  van3prod_edit->setText( QString("%1").arg(par.van3prod) );
 
  van3autokat_edit->setText( QString("%1").arg(par.van3autokat) );
 
  van3sat_edit->setText( QString("%1").arg(par.van3sat) );
 
  k2van3_edit->setText( QString("%1").arg(par.k2van3) );
 
  dt_edit->setText( QString("%1").arg(par.dt) );
 
  rd_dt_edit->setText( QString("%1").arg(par.rd_dt) );
 
  datadir_edit->setText( QString("%1").arg(par.datadir) );
 
  movie_edit->setText( QString("%1").arg(sbool(par.movie)));
 
  nit_edit->setText( QString("%1").arg(par.nit) );
 
  maxt_edit->setText( QString("%1").arg(par.maxt) );
 
  storage_stride_edit->setText( QString("%1").arg(par.storage_stride) );
 
  xml_storage_stride_edit->setText( QString("%1").arg(par.xml_storage_stride) );
 
  rseed_edit->setText( QString("%1").arg(par.rseed) );
 
  constituous_expansion_limit_edit->setText( QString("%1").arg(par.constituous_expansion_limit) );
 
  vessel_inh_level_edit->setText( QString("%1").arg(par.vessel_inh_level) );
 
  vessel_expansion_rate_edit->setText( QString("%1").arg(par.vessel_expansion_rate) );
 
  d_edit->setText( QString("%1").arg(par.d) );
 
  e_edit->setText( QString("%1").arg(par.e) );
 
  f_edit->setText( QString("%1").arg(par.f) );
 
  c_edit->setText( QString("%1").arg(par.c) );
 
  mu_edit->setText( QString("%1").arg(par.mu) );
 
  nu_edit->setText( QString("%1").arg(par.nu) );
 
  rho0_edit->setText( QString("%1").arg(par.rho0) );
 
  rho1_edit->setText( QString("%1").arg(par.rho1) );
 
  c0_edit->setText( QString("%1").arg(par.c0) );
 
  gamma_edit->setText( QString("%1").arg(par.gamma) );
 
  eps_edit->setText( QString("%1").arg(par.eps) );
 
  QString k_string("%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12,%13,%14,%15");
 
  k_string = k_string.arg(par.k[0]).arg(par.k[1]).arg(par.k[2]).arg(par.k[3]).arg(par.k[4]).arg(par.k[5]).arg(par.k[6]).arg(par.k[7]).arg(par.k[8]).arg(par.k[9]).arg(par.k[10]).arg(par.k[11]).arg(par.k[12]).arg(par.k[13]).arg(par.k[14]);
 
  k_edit->setText( k_string );
 
  i1_edit->setText( QString("%1").arg(par.i1) );
 
  i2_edit->setText( QString("%1").arg(par.i2) );
 
  i3_edit->setText( QString("%1").arg(par.i3) );
 
  i4_edit->setText( QString("%1").arg(par.i4) );
 
  i5_edit->setText( QString("%1").arg(par.i5) );
 
  s1_edit->setText( QString("%1").arg(par.s1) );
 
  s2_edit->setText( QString("%1").arg(par.s2) );
 
  s3_edit->setText( QString("%1").arg(par.s3) );
 
  b1_edit->setText( QString("%1").arg(sbool(par.b1)));
 
  b2_edit->setText( QString("%1").arg(sbool(par.b2)));
 
  b3_edit->setText( QString("%1").arg(sbool(par.b3)));
 
  b4_edit->setText( QString("%1").arg(sbool(par.b4)));
 
  dir1_edit->setText( QString("%1").arg(par.dir1) );
 
  dir2_edit->setText( QString("%1").arg(par.dir2) );
 
}
 

	
src/pardialog.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#ifndef PARAMETER_DIALOG_H
 
#define PARAMETER_DIALOG_H
 
#include <qdialog.h>
 
#include <qspinbox.h>
 
#include <qlineedit.h>
 
#include <qlayout.h>
 
#include <qpushbutton.h>
 
#include <iostream>
 

	
 
class ParameterDialog : public QDialog {
 
  Q_OBJECT
 
 
 
  public:
 

	
 
    public:
 
  ParameterDialog(QWidget *parent=0, const char *name = 0, Qt::WindowFlags f = 0);
 
  virtual ~ParameterDialog(void);
 
 public slots:
 
  public slots:
 
  void Reset(void);
 

	
 
private slots:
 
  private slots:
 
  void write(void);
 

	
 
 private:
 
  QLineEdit *arrowcolor_edit;
 
  QLineEdit *arrowsize_edit;
 
  QLineEdit *textcolor_edit;
 
  QLineEdit *cellnumsize_edit;
 
  QLineEdit *nodenumsize_edit;
 
  QLineEdit *node_mag_edit;
 
  QLineEdit *outlinewidth_edit;
 
  QLineEdit *cell_outline_color_edit;
 
  QLineEdit *resize_stride_edit;
 
  QLineEdit *T_edit;
 
  QLineEdit *lambda_length_edit;
 
  QLineEdit *lambda_celllength_edit;
 
  QLineEdit *target_length_edit;
 
  QLineEdit *cell_expansion_rate_edit;
 
  QLineEdit *cell_div_expansion_rate_edit;
 
  QLineEdit *auxin_dependent_growth_edit;
 
  QLineEdit *ode_accuracy_edit;
 
  QLineEdit *mc_stepsize_edit;
 
  QLineEdit *mc_cell_stepsize_edit;
 
  QLineEdit *energy_threshold_edit;
 
  QLineEdit *bend_lambda_edit;
 
  QLineEdit *alignment_lambda_edit;
 
  QLineEdit *rel_cell_div_threshold_edit;
 
  QLineEdit *rel_perimeter_stiffness_edit;
 
  QLineEdit *collapse_node_threshold_edit;
 
  QLineEdit *morphogen_div_threshold_edit;
 
  QLineEdit *morphogen_expansion_threshold_edit;
 
  QLineEdit *copy_wall_edit;
 
  QLineEdit *source_edit;
 
  QLineEdit *D_edit;
 
  QLineEdit *initval_edit;
 
  QLineEdit *k1_edit;
 
  QLineEdit *k2_edit;
 
  QLineEdit *r_edit;
 
  QLineEdit *kr_edit;
 
  QLineEdit *km_edit;
 
  QLineEdit *Pi_tot_edit;
 
  QLineEdit *transport_edit;
 
  QLineEdit *ka_edit;
 
  QLineEdit *pin_prod_edit;
 
  QLineEdit *pin_prod_in_epidermis_edit;
 
  QLineEdit *pin_breakdown_edit;
 
  QLineEdit *pin_breakdown_internal_edit;
 
  QLineEdit *aux1prod_edit;
 
  QLineEdit *aux1prodmeso_edit;
 
  QLineEdit *aux1decay_edit;
 
  QLineEdit *aux1decaymeso_edit;
 
  QLineEdit *aux1transport_edit;
 
  QLineEdit *aux_cons_edit;
 
  QLineEdit *aux_breakdown_edit;
 
  QLineEdit *kaux1_edit;
 
  QLineEdit *kap_edit;
 
  QLineEdit *leaf_tip_source_edit;
 
  QLineEdit *sam_efflux_edit;
 
  QLineEdit *sam_auxin_edit;
 
  QLineEdit *sam_auxin_breakdown_edit;
 
  QLineEdit *van3prod_edit;
 
  QLineEdit *van3autokat_edit;
 
  QLineEdit *van3sat_edit;
 
  QLineEdit *k2van3_edit;
 
  QLineEdit *dt_edit;
 
  QLineEdit *rd_dt_edit;
 
  QLineEdit *datadir_edit;
 
  QLineEdit *movie_edit;
 
  QLineEdit *nit_edit;
 
  QLineEdit *maxt_edit;
 
  QLineEdit *storage_stride_edit;
 
  QLineEdit *xml_storage_stride_edit;
 
  QLineEdit *rseed_edit;
 
  QLineEdit *constituous_expansion_limit_edit;
 
  QLineEdit *vessel_inh_level_edit;
 
  QLineEdit *vessel_expansion_rate_edit;
 
  QLineEdit *d_edit;
 
  QLineEdit *e_edit;
 
  QLineEdit *f_edit;
 
  QLineEdit *c_edit;
 
  QLineEdit *mu_edit;
 
  QLineEdit *nu_edit;
 
  QLineEdit *rho0_edit;
 
  QLineEdit *rho1_edit;
 
  QLineEdit *c0_edit;
 
  QLineEdit *gamma_edit;
 
  QLineEdit *eps_edit;
 
  QLineEdit *k_edit;
 
  QLineEdit *i1_edit;
 
  QLineEdit *i2_edit;
 
  QLineEdit *i3_edit;
 
  QLineEdit *i4_edit;
 
  QLineEdit *i5_edit;
 
  QLineEdit *s1_edit;
 
  QLineEdit *s2_edit;
 
  QLineEdit *s3_edit;
 
  QLineEdit *b1_edit;
 
  QLineEdit *b2_edit;
 
  QLineEdit *b3_edit;
 
  QLineEdit *b4_edit;
 
  QLineEdit *dir1_edit;
 
  QLineEdit *dir2_edit;
 
};
 
#endif
src/parse.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 
 
#include <stdio.h>
 
#include <string.h>
 
#include <stdlib.h>
 
#include <errno.h>
 
#include <string.h>
 
#include "warning.h"
 
#include "parse.h"
 
#include "output.h"
 
#include <string>
 
 
static const std::string _module_id("$Id$");
 
 
using namespace MyWarning;
 
 
char *ParsePar(FILE *fp, char *parameter, bool wrapflag) 
 
{
 
  char *line,*token;
 
  char *value;
 
  
 
 
  line=SearchToken(fp,parameter, wrapflag);
 
  if (line==NULL) {
 
    warning("Warning: Token %s not found.",parameter);
 
    value=0;
 
    return value;
 
  }
 
  
 
 
  /* parse the line on = sign */
 
  token=strtok(line,"=");
 
  if (token==NULL) {
 
	error("Parse error: no '=' sign found next to token %s, in line: \n %s.",
 
		  parameter,line);
 
   }
 
    error("Parse error: no '=' sign found next to token %s, in line: \n %s.",
 
	  parameter,line);
 
  }
 
 
  // warning("Reading value for token %s...",token);
 
  fprintf(stderr, "[%s = ",token);
 
  
 
 
  token=strtok(NULL,"=");
 
  if (token==NULL)
 
	error("\nParse error: no value found after '=' sign, in line: \n %s",
 
		  line);
 
    error("\nParse error: no value found after '=' sign, in line: \n %s",
 
	  line);
 
 
  value=strdup(token);
 
  free(line);
 
  
 
 
  return value;
 
      
 
}
 
 
 
int igetpar(FILE *fp,char *parameter, bool wrapflag) {
 
  
 
 
  // overloaded compatibility function. Doesn't need default parameter
 
 
  return igetpar(fp, parameter, 0, wrapflag);
 
}
 
 
int igetpar(FILE *fp,char *parameter, int default_val, bool wrapflag) 
 
{
 
  char *token;
 
  int value;
 
  
 
 
  /* Get token representing the value */
 
  token=ParsePar(fp,parameter, wrapflag);
 
 
  if (token==0) {
 
    /* default value */
 
    warning("No token %s found. Using default value %d.\n", parameter, default_val);
 
    return default_val;
 
  }
 
  /* read it */
 
  sscanf(token,"%d",&value);
 
  fprintf(stderr, "%d]\n",value);
 
  
 
 
  free(token);
 
 
  return value;
 
  
 
}
 
 
float fgetpar(FILE *fp,char *parameter, bool wrapflag) {
 
   
 
 
  // overloaded compatibility function. Doesn't need default parameter
 
  return fgetpar(fp, parameter, 0., wrapflag);
 
}
 
 
float fgetpar(FILE *fp, char *parameter, double default_val, bool wrapflag) 
 
{
 
  char *token;
 
  float value;
 
 
  /* Get token representing the value */
 
  token=ParsePar(fp,parameter, wrapflag);
 
 
  if (token==0) {
 
    /* default value */
 
    warning("No token %s found. Using default value %f.\n", parameter, default_val);
 
    return default_val;
 
  }
 
 
  /* read it */
 
  sscanf(token,"%e",&value);
 
 
  fprintf(stderr,"%e]\n",value);
 
  
 
  free(token);
 
 
  return value;
 
  
 
}
 
 
 
double *dgetparlist(FILE *fp,char *parameter, int n, bool wrapflag) 
 
{
 
  /* Get a list of n comma separated doubles */
 
  char *token;
 
  double *value;
 
  char *number;
 
  int i;
 
 
  value=(double *)malloc(n*sizeof(double));
 
  
 
 
  /* Get token representing the value */
 
  token=ParsePar(fp,parameter, wrapflag);
 
  
 
 
  if (token==0) {
 
    error("No token %s found.\n", parameter);
 
  }
 
  /* parse it */
 
  number=strtok(token,","); /* make a pointer to "token" */
 
  
 
 
  i=0;
 
  while (number!=NULL) {
 
    
 
 
    if (i>=n) {
 
      error("\nToo many values found for parameterlist '%s' (%d expected).",parameter,n);
 
    }
 
    
 
 
    sscanf(number,"%le",&value[i]);
 
    fprintf(stderr,"[%f]",value[i]);
 
    
 
 
    /* next value */
 
    number=strtok(NULL,",");
 
    i++;
 
  }
 
  
 
 
  fprintf(stderr,"]\n");
 
  
 
 
  if (i<n) {
 
    warning("Too few values found for parameterlist '%s' (%d expected).", parameter,n);
 
    warning("Padding with 0.");
 
    for (int j=i;j<n;j++) 
 
      value[j]=0.;
 
    
 
 
    fprintf(stderr, "Full array is ");
 
    for (int i=0;i<n;i++) {
 
      fprintf(stderr," %lf ",value[i]);
 
    }
 
    fprintf(stderr, "\n");
 
  }
 
  
 
 
  return value;
 
  
 
}
 
 
char *sgetpar(FILE *fp,char *parameter, bool wrapflag) 
 
{
 
  return sgetpar(fp, parameter, " ", wrapflag);
 
}
 
 
char *sgetpar(FILE *fp, char *parameter, const char *default_val, bool wrapflag) {
 
 
  char *token;
 
  char *value;
 
  int pos;
 
    
 
 
  /* Get token representing the value */
 
  token=ParsePar(fp,parameter, wrapflag);
 
 
  if (token==0) {
 
    /* default value */
 
    warning("No token %s found. Using default value '%s'.\n", parameter, default_val);
 
    value=strdup(default_val);
 
    return value;
 
  }
 
  
 
 
  /* strip leading spaces and duplicate string */
 
  pos=strspn(token," \t\n");
 
  value=(char *)malloc((strlen(&token[pos])+1)*sizeof(char));
 
  sprintf(value,"%s",&token[pos]);
 
  free(token);
 
 
  fprintf(stderr,"%s]\n",value);
 
 
  return value;
 
  
 
}
 
 
char *bool_str(bool bool_var) {
 
  
 
 
  /* Return string "true" if bool_var=true */
 
  /* Return string "false" if bool_var=false */
 
  
 
 
  static char t[5] = "true";
 
  static char f[6] = "false";
 
 
  if (bool_var) {
 
    return t;
 
  } else {
 
    return f;
 
  }
 
  
 
}
 
 
bool bgetpar(FILE *fp, char *parameter,  bool wrapflag) {
 
  
 
 
  // overloaded compatibility function. Doesn't need default parameter
 
  // default = false
 
 
  return bgetpar(fp, parameter, 0, wrapflag);
 
 
}
 
 
bool bgetpar(FILE *fp, char *parameter, int default_val, bool wrapflag) {
 
 
  /* Get boolean parameter. */
 
  /* if "true" or "yes", return 1 */
 
  /* if "false" or "no", return 0 */
 
  /* else complain */
 
 
  char *token;
 
  int value=0;
 
  int pos;
 
    
 
 
  /* Get token representing the value */
 
  token=ParsePar(fp,parameter, wrapflag);
 
 
  if (token==0) {
 
    /* default value */
 
    warning("No token %s found. Using default value %s.\n", parameter, bool_str(default_val));
 
    return default_val;
 
  }
 
 
    
 
 
  /* strip leading spaces */
 
  pos=strspn(token," \t\n");
 
  
 
 
  if (!strcmp(&token[pos],"yes") || !strcmp(&token[pos],"true") || !strcmp(&token[pos],"1"))
 
    value=1;
 
  else 
 
    if (!strcmp(&token[pos],"no") || !strcmp(&token[pos],"false") || !strcmp(&token[pos],"0"))
 
      value=0;
 
  else
 
    error("Keyword '%s' not recognized. Try yes/no or true/false.\n",&token[pos]);
 
    else
 
      error("Keyword '%s' not recognized. Try yes/no or true/false.\n",&token[pos]);
 
 
  fprintf(stderr, "%s]\n",bool_str(value));
 
 
  return value;
 
 
}
 
 
 
char *SearchToken(FILE *fp, char *token,bool wrapflag) 
 
{
 
  /* This function returns the next line of FILE *fp that contains
 
     the string stored in the null terminated string token */
 
 
  /* remember to free the memory allocated for line */
 
  
 
 
  unsigned int len;
 
  char *line;
 
  int wrapped=false;
 
  long initial_position;
 
  
 
 
  char *tokenplusspace = (char *)malloc( (strlen(token)+3)*sizeof(char));
 
  strcpy(tokenplusspace, token);
 
  strcat(tokenplusspace," ");
 
  
 
 
  initial_position=ftell(fp);
 
  if (ferror(fp)) /* error occured */
 
    {
 
      error("%s",strerror(errno));
 
    }
 
 
 
 
 
  if (feof(fp)) {
 
    warning("End of file\n");
 
  }
 
  
 
  
 
 
 
  while (!(wrapped && ftell(fp)>=initial_position)) {
 
 
    /* As long as the search was not wrapped and we are not
 
     * back to where we were, continue searching */
 
		
 
 
    /* Read a line, and check whether an EOF was found */
 
    if ((line=ReadLine(fp))==NULL) {
 
      /* Yes? wrapflag on? => Wrap. */
 
      if (wrapflag) {
 
	wrapped=true;
 
	fseek(fp,0L,SEEK_SET);
 
	continue;
 
      } else 
 
	break;
 
    }
 
 
    /* strip leading spaces */
 
    int pos=strspn(line," \t\n");
 
 
    if (line[pos]=='#') {
 
     
 
 
      continue;
 
    } 
 
    
 
 
    len=strlen(line);
 
    if (strlen(tokenplusspace)<=len) {
 
 
      /* only if the line is longer than the token, it might be found */
 
      // if (strstr(line,tokenplusspace)!=NULL) /* FOUND */
 
      if (strstr(line,tokenplusspace)==(&line[pos])) /* FOUND */
 
	{
 
	  free(tokenplusspace);
 
	  return line;
 
	}
 
    }
 
    
 
 
    free(line);
 
    
 
  }
 
  free(tokenplusspace);
 
  return NULL; /* Token Not Found in the file */
 
}
 
 
int TokenInLineP(char *line,char *token) 
 
{
 
  if (strstr(token, line)!=NULL)
 
    return true;
 
  else
 
    return false;
 
}
 
 
 
void SkipLine(FILE *fp) {
 
  
 
 
  /* Just skips a line in FILE *fp */
 
  char *tmpstring;
 
  tmpstring=ReadLine(fp);
 
  free(tmpstring);
 
  
 
}
 
 
void SkipToken(FILE *fp,char *token, bool wrapflag)
 
{
 
  /* A very simple function:
 
	 call SearchToken() and get rid of the memory returned by
 
     call SearchToken() and get rid of the memory returned by
 
     it.
 
	 Also, return an error if the desired token was not found in the file.
 
     Also, return an error if the desired token was not found in the file.
 
  */
 
  char *tmppointer;
 
 
  tmppointer=SearchToken(fp,token, wrapflag);
 
 
  if (tmppointer==NULL) {
 
	error("Token `%s' not found by function SkipToken.\n",token);
 
    error("Token `%s' not found by function SkipToken.\n",token);
 
  }
 
 
  free(tmppointer);
 
      
 
}
 
 
/* finis */
src/parse.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _PARSE_H_
 
#define _PARSE_H_
 

	
 
char *ParsePar(FILE *fp, char *parameter, bool wrapflag);
 
int igetpar(FILE *fp,char *parameter, bool wrapflag);
 
int igetpar(FILE *fp,char *parameter, int default_val, bool wrapflag);
 
float fgetpar(FILE *fp,char *parameter, bool wrapflag);
 
float fgetpar(FILE *fp,char *parameter, double default_val, bool wrapflag);
 

	
 
/* Get a list of n comma separated doubles */
 
double *dgetparlist(FILE *fp,char *parameter, int n, bool wrapflag);
 
char *sgetpar(FILE *fp,char *parameter, bool wrapflag);
 
char *sgetpar(FILE *fp,char *parameter,const char *default_val, bool wrapflag);
 
bool bgetpar(FILE *fp, char *parameter, bool wrapflag);
 
bool bgetpar(FILE *fp, char *parameter, int default_val, bool wrapflag);
 
char *SearchToken(FILE *fp, char *token, bool wrapflag);
 
int TokenInLineP(char *line,char *token);
 
void SkipToken(FILE *fp,char *token, bool wrapflag);
 
void SkipLine(FILE *fp);
 
char *bool_str(bool bool_var);
 

	
 
#endif
 

	
 
/* finis */
src/perl/deployapp.pl
Show inline comments
 
#!/usr/bin/perl
 

	
 
#
 
# $Id$
 
#
 
#  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 <http://www.gnu.org/licenses/>.
 
#
 
#  Copyright 2010 Roeland Merks.
 
#
 
#
 

	
 
# get dependencies for executable
 
sub get_frameworks {
 
  my $exec = shift;
 
  my @frameworks = ();
 
  my $fw;
 
    my $exec = shift;
 
    my @frameworks = ();
 
    my $fw;
 
#  print "get_frameworks says: exec = $exec\n";
 
  open deps, "otool -L $exec |";
 
  # omit first line
 
  <deps>;
 
    open deps, "otool -L $exec |";
 
    # omit first line
 
    <deps>;
 

	
 
  while (<deps>) {
 
    # look for lines with ".framework", that do not start with / or @.
 
    if (/\.framework/ && !/^[ \t]*\// && !/^[ \t]*\@/) {
 
      chomp;
 
      @line = split;
 
      $f = $line[0];
 
      # get framework directory name
 
      @line = split(/\//,$f);
 
      for $d (@line) {
 
	if ($d =~ /\.framework/) {
 
	  $fw = $d; 
 
    while (<deps>) {
 
	# look for lines with ".framework", that do not start with / or @.
 
	if (/\.framework/ && !/^[ \t]*\// && !/^[ \t]*\@/) {
 
	    chomp;
 
	    @line = split;
 
	    $f = $line[0];
 
	    # get framework directory name
 
	    @line = split(/\//,$f);
 
	    for $d (@line) {
 
		if ($d =~ /\.framework/) {
 
		    $fw = $d; 
 
#          print "get_framework finds framework $d\n";
 
	  last;
 
	}
 
      }
 
      if (defined($fw)) {
 
		    last;
 
		}
 
	    }
 
	    if (defined($fw)) {
 
#	print "get_frameworks pushes $fw on stack\n";
 
	push @frameworks, $fw;
 
      }
 
    } 
 
  }
 
 @frameworks;
 
		push @frameworks, $fw;
 
	    }
 
	} 
 
    }
 
    @frameworks;
 
}
 

	
 
$app = $ARGV[0];
 
$appdir = $app.".app";
 
if ($appdir =~ /\.app\.app/) {
 
  $appdir = $ARGV[0];
 
    $appdir = $ARGV[0];
 
}
 
$exec = $appdir."/Contents/MacOS/$app";
 

	
 
@frameworks = get_frameworks( $exec );
 

	
 
#for $f (@frameworks) {
 
#  print "$f\n";
 
#}
 

	
 
# copy all frameworks to appdir/frameworks
 

	
 
system ("mkdir $appdir/Contents/Frameworks");
 
for $fw (@frameworks) {
 
   system "cp -R /Library/Frameworks/$fw $appdir/Contents/Frameworks/.";
 
    system "cp -R /Library/Frameworks/$fw $appdir/Contents/Frameworks/.";
 
}
 

	
 

	
 
# set identification names for the frameworks
 

	
 
for $fw (@frameworks) {
 
   $lib = $fw; $lib =~ s/\.framework//g;
 
   system "install_name_tool -id \@executable_path/../Frameworks/$fw/Versions/4.0/$lib $appdir/Contents/Frameworks/$fw/Versions/4.0/$lib";
 
    $lib = $fw; $lib =~ s/\.framework//g;
 
    system "install_name_tool -id \@executable_path/../Frameworks/$fw/Versions/4.0/$lib $appdir/Contents/Frameworks/$fw/Versions/4.0/$lib";
 

	
 
   
 
   # tell dynamic linker where to look for the frameworks
 
   system "install_name_tool -change $fw/Versions/4/$lib \@executable_path/../Frameworks/$fw/Versions/4.0/$lib $appdir/Contents/MacOs/$app";
 
   
 
    
 
    # tell dynamic linker where to look for the frameworks
 
    system "install_name_tool -change $fw/Versions/4/$lib \@executable_path/../Frameworks/$fw/Versions/4.0/$lib $appdir/Contents/MacOs/$app";
 
    
 
}
 

	
 

	
 
# now, set the frameworks' reciprocal dependencies right
 
for $fw (@frameworks) {
 
  $lib = $fw; $lib =~ s/\.framework//g;
 
  my @frameworks_of_fw = get_frameworks ( "$appdir/Contents/Frameworks/$fw/Versions/4.0/$lib" );
 
  for $fwfw (@frameworks_of_fw) {
 
    $lib = $fw; $lib =~ s/\.framework//g;
 
    my @frameworks_of_fw = get_frameworks ( "$appdir/Contents/Frameworks/$fw/Versions/4.0/$lib" );
 
    for $fwfw (@frameworks_of_fw) {
 
#    print "$fwfw\n";
 
    $liblib = $fwfw; $liblib =~ s/\.framework//g;    
 
     system "install_name_tool -change $fwfw/Versions/4/$liblib \@executable_path/../Frameworks/$fwfw/Versions/4.0/$liblib  $appdir/Contents/Frameworks/$fw/Versions/4.0/$lib";
 
  }
 
	$liblib = $fwfw; $liblib =~ s/\.framework//g;    
 
	system "install_name_tool -change $fwfw/Versions/4/$liblib \@executable_path/../Frameworks/$fwfw/Versions/4.0/$liblib  $appdir/Contents/Frameworks/$fw/Versions/4.0/$lib";
 
    }
 
}
 

	
 
# do the same for additional libs not in a framework depending on frameworks (e.g. libqwt...)
 
@additionallibs = ( "libqwt.dylib" );
 

	
 
for $lib (@additionallibs) {
 
  my @frameworks_of_lib = get_frameworks ( "$appdir/Contents/Frameworks/$lib" );
 
  for $fwfw (@frameworks_of_lib) {
 
    #    print "$fwfw\n";
 
    $liblib = $fwfw; $liblib =~ s/\.framework//g;    
 
    system "install_name_tool -change $fwfw/Versions/4/$liblib \@executable_path/../Frameworks/$fwfw/Versions/4.0/$liblib  $appdir/Contents/Frameworks/$lib";
 
  }
 
    my @frameworks_of_lib = get_frameworks ( "$appdir/Contents/Frameworks/$lib" );
 
    for $fwfw (@frameworks_of_lib) {
 
	#    print "$fwfw\n";
 
	$liblib = $fwfw; $liblib =~ s/\.framework//g;    
 
	system "install_name_tool -change $fwfw/Versions/4/$liblib \@executable_path/../Frameworks/$fwfw/Versions/4.0/$liblib  $appdir/Contents/Frameworks/$lib";
 
    }
 
}
 

	
 
# finis
src/perl/histogram.pl
Show inline comments
 
#!/usr/bin/perl
 

	
 
#
 
# $Id$
 
#
 
#  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 <http://www.gnu.org/licenses/>.
 
#
 
#  Copyright 2010 Roeland Merks.
 
#
 
#
 

	
 
$n_bins=100;
 
$min=0.;
 
$max=8*atan2(1,1); # 2 Pi
 
$binsize = ($max-$min)/$n_bins;
 

	
 

	
 
for ($i=0;$i<$n_bins;$i++) {
 
	$bins[$i]=0;
 
    $bins[$i]=0;
 
}
 

	
 
while (<>) {
 
  @line=split;
 
  $num=$line[0];
 
  $bin = int($num / $binsize);
 
	# print "[$num, $bin] ";
 
  $bins[$bin]++;
 
    @line=split;
 
    $num=$line[0];
 
    $bin = int($num / $binsize);
 
    # print "[$num, $bin] ";
 
    $bins[$bin]++;
 
}
 

	
 

	
 
for ($bin=0;$bin<=$#bins;$bin++) {
 
   $halfwaybin = $bin * $binsize + $binsize/2.;
 
   print $halfwaybin." ".$bins[$bin]."\n";
 
    $halfwaybin = $bin * $binsize + $binsize/2.;
 
    print $halfwaybin." ".$bins[$bin]."\n";
 
}
 

	
 
# finis
 

	
src/perl/make_parameter_source.pl
Show inline comments
 
#!/usr/bin/perl 
 

	
 
#
 
# $Id$
 
#
 
#  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 <http://www.gnu.org/licenses/>.
 
#
 
#  Copyright 2010 Roeland Merks.
 
#
 

	
 
# input: parameter file + types
 
# format: par_name = default_value/type
 

	
 
# output: C++ source code of class Parameter
 
# and sample parameter file
 

	
 
%funname = (
 
	    "double" => fgetpar,
 
	    "float" => fgetpar,
 
	    "int" => igetpar,
 
	    "bool" => bgetpar,
 
	    "char *" => sgetpar,
 
	    "string" => sgetpar,
 
	    "double *" => dgetparlist,
 
	   );
 
    "double" => fgetpar,
 
    "float" => fgetpar,
 
    "int" => igetpar,
 
    "bool" => bgetpar,
 
    "char *" => sgetpar,
 
    "string" => sgetpar,
 
    "double *" => dgetparlist,
 
    );
 

	
 
%typetrans = (
 
	      "double" => "double",
 
	      "float" => "double",
 
	      "int" => "int",
 
	      "bool" => "bool",
 
	      "char *" => "char *",
 
	      "string" => "char *",
 
	      "directory" => "char *",
 
	      "doublelist" => "double *",
 
	      "label" => "label",
 
	      "title" => "title",
 
);
 
    "double" => "double",
 
    "float" => "double",
 
    "int" => "int",
 
    "bool" => "bool",
 
    "char *" => "char *",
 
    "string" => "char *",
 
    "directory" => "char *",
 
    "doublelist" => "double *",
 
    "label" => "label",
 
    "title" => "title",
 
    );
 

	
 
open parfile,"<$ARGV[0]";
 
open cppfile,">parameter.cpp";
 
$i=0;
 
while (<parfile>) {
 
#ignore comments
 
  if (/^#/) {
 
    next;
 
  }
 
  @line=split(/=/);
 
    if (/^#/) {
 
	next;
 
	}
 
    @line=split(/=/);
 
#ignore empty lines
 
  if ($#line<1) {
 
    next;
 
  }
 
  $param[$i]=$line[0];
 
  $value_type=$line[1];
 
    if ($#line<1) {
 
	next;
 
    }
 
    $param[$i]=$line[0];
 
    $value_type=$line[1];
 

	
 
  @typel=split(/ \/ /,$value_type);
 
  $value[$i] = $typel[0];
 
  $type[$i] = $typel[1];
 
  
 
    @typel=split(/ \/ /,$value_type);
 
    $value[$i] = $typel[0];
 
    $type[$i] = $typel[1];
 
    
 
#get rid of spaces
 
  $param[$i] =~ s/ //g;
 
  $value[$i] =~ s/ //g;
 
  $type[$i] =~ s/ //g;
 
  $type[$i] =~s/\n//g;
 
  $convtype[$i]=$typetrans{$type[$i]};
 
    $param[$i] =~ s/ //g;
 
    $value[$i] =~ s/ //g;
 
    $type[$i] =~ s/ //g;
 
    $type[$i] =~s/\n//g;
 
    $convtype[$i]=$typetrans{$type[$i]};
 

	
 
  if ($convtype[$i] eq "char *") {
 
    $value[$i] = "\"$value[$i]\"";
 
  }
 
  #print cppfile "param = $param, value = $value, type = $type\n";
 
    if ($convtype[$i] eq "char *") {
 
	$value[$i] = "\"$value[$i]\"";
 
    }
 
    #print cppfile "param = $param, value = $value, type = $type\n";
 

	
 
  $i++;
 
    $i++;
 
}
 

	
 
$lines=$i;
 

	
 
print cppfile <<END_HEADER;
 
// WARNING: This file is automatically generated by make_parameter_source.pl. Do not edit.
 
// All edits will be discarded.
 
    // All edits will be discarded.
 

	
 
#include "parameter.h"
 
#include <cstdio>
 
#include <cstring>
 
#include <cstdlib>
 
#include <cerrno>
 
#include <iostream>
 
#include <sstream>
 
#include "output.h"
 
#include "parse.h"
 
#include "xmlwrite.h"
 
#include "warning.h"
 
#include <QLocale>
 

	
 
using namespace std;
 
    using namespace std;
 

	
 

	
 
Parameter::Parameter() {
 
END_HEADER
 
    END_HEADER
 

	
 
for ($i=0;$i<$lines;$i++) {
 
  if ($convtype[$i] ne "label" && $convtype[$i] ne "title") {
 
    if ($convtype[$i] eq "char *") {
 
      print cppfile "  $param[$i] = strdup($value[$i]);\n";
 
    } else {
 
      if ($convtype[$i] eq "double *") {
 
	#comma separated list expected
 
	@paramlist = split(/,/, $value[$i]);
 
	$length = $#paramlist+1;
 
	print cppfile "  $param[$i] = new double\[$length\];\n";
 
	for ($j=0;$j<=$#paramlist;$j++) {
 
	  print cppfile "  $param[$i]\[$j\] = $paramlist[$j];\n";
 
	}
 
      } else {
 
	print cppfile "  $param[$i] = $value[$i];\n";
 
      }
 
	for ($i=0;$i<$lines;$i++) {
 
	    if ($convtype[$i] ne "label" && $convtype[$i] ne "title") {
 
		if ($convtype[$i] eq "char *") {
 
		    print cppfile "  $param[$i] = strdup($value[$i]);\n";
 
		} else {
 
		    if ($convtype[$i] eq "double *") {
 
			#comma separated list expected
 
			@paramlist = split(/,/, $value[$i]);
 
			$length = $#paramlist+1;
 
			print cppfile "  $param[$i] = new double\[$length\];\n";
 
			for ($j=0;$j<=$#paramlist;$j++) {
 
			    print cppfile "  $param[$i]\[$j\] = $paramlist[$j];\n";
 
			}
 
		    } else {
 
			print cppfile "  $param[$i] = $value[$i];\n";
 
		    }
 
		}
 
	    }
 
    }
 
 }
 
}
 

	
 

	
 
print cppfile <<END_HEADER3;
 
    print cppfile <<END_HEADER3;
 
}
 

	
 
Parameter::~Parameter() {
 
  
 
  // destruct parameter object
 
    
 
    // destruct parameter object
 

	
 
  // free string parameter
 
	// free string parameter
 

	
 
  CleanUp();
 
	CleanUp();
 

	
 
}
 

	
 
void Parameter::CleanUp(void) {
 
END_HEADER3
 
    END_HEADER3
 

	
 
for ($i=0;$i<$lines;$i++) {
 
  if ($convtype[$i] eq "char *" || $convtype[$i] eq "double *") {
 
    print cppfile "  if ($param[$i]) \n";
 
    print cppfile "     free($param[$i]);\n";
 
  }
 
}
 
print cppfile <<END_HEADER4;
 
	for ($i=0;$i<$lines;$i++) {
 
	    if ($convtype[$i] eq "char *" || $convtype[$i] eq "double *") {
 
		print cppfile "  if ($param[$i]) \n";
 
		print cppfile "     free($param[$i]);\n";
 
	    }
 
    }
 
    print cppfile <<END_HEADER4;
 

	
 
}
 

	
 
void Parameter::Read(const char *filename) {
 
  
 
  static bool ReadP=false;
 
    
 
    static bool ReadP=false;
 

	
 
  if (ReadP) {
 
    if (ReadP) {
 

	
 
    //throw "Run Time Error in parameter.cpp: Please Read parameter file only once!!";
 
    CleanUp();
 
    
 
  } else
 
    ReadP=true;
 
	//throw "Run Time Error in parameter.cpp: Please Read parameter file only once!!";
 
	CleanUp();
 
	
 
    } else
 
	ReadP=true;
 

	
 
  FILE *fp=OpenReadFile(filename);
 
    FILE *fp=OpenReadFile(filename);
 

	
 

	
 
END_HEADER4
 
    END_HEADER4
 

	
 
for ($i=0;$i<$lines;$i++) {
 
	for ($i=0;$i<$lines;$i++) {
 

	
 
  if ($convtype[$i] eq "label" || $convtype[$i] eq "title") {
 
    next;
 
  }
 
  if ($convtype[$i] eq "double *") {
 
    @paramlist = split(/,/,$value[$i]);
 
    $length = $#paramlist+1;
 
    print cppfile "  $param[$i] = $funname{$convtype[$i]}(fp, \"$param[$i]\", $length, true);\n";
 
  } else {
 
    print cppfile "  $param[$i] = $funname{$convtype[$i]}(fp, \"$param[$i]\", $value[$i], true);\n";
 
  }
 
  if ($type[$i] eq "directory") {
 
	    if ($convtype[$i] eq "label" || $convtype[$i] eq "title") {
 
		next;
 
	    }
 
	    if ($convtype[$i] eq "double *") {
 
		@paramlist = split(/,/,$value[$i]);
 
		$length = $#paramlist+1;
 
		print cppfile "  $param[$i] = $funname{$convtype[$i]}(fp, \"$param[$i]\", $length, true);\n";
 
	    } else {
 
		print cppfile "  $param[$i] = $funname{$convtype[$i]}(fp, \"$param[$i]\", $value[$i], true);\n";
 
	    }
 
	    if ($type[$i] eq "directory") {
 

	
 
    print cppfile "  if (strcmp($param[$i], \".\"))\n";
 
    print cppfile "    MakeDir($param[$i]);\n";
 
  }
 
}
 
		print cppfile "  if (strcmp($param[$i], \".\"))\n";
 
		print cppfile "    MakeDir($param[$i]);\n";
 
	    }
 
    }
 

	
 

	
 

	
 
print cppfile <<END_MIDPART;
 
    print cppfile <<END_MIDPART;
 

	
 
}
 

	
 
const char *sbool(const bool &p) {
 

	
 
  const char *true_str="true";
 
  const char *false_str="false";
 
  if (p)
 
    return true_str;
 
  else
 
    return false_str;
 
    const char *true_str="true";
 
    const char *false_str="false";
 
    if (p)
 
	return true_str;
 
    else
 
	return false_str;
 
}
 

	
 
void Parameter::Write(ostream &os) const {
 

	
 
END_MIDPART
 
    END_MIDPART
 

	
 
for ($i=0;$i<$lines;$i++) {
 
 
 
  if ($convtype[$i] eq "label"  || $convtype[$i] eq "title") {
 
    next;
 
  }
 
  if ($convtype[$i] eq "double *") {
 
    print cppfile "  os << \" $param[$i] = \"";
 
    @paramlist = split(/,/,$value[$i]);
 
    for ($j=0;$j<$#paramlist;$j++) {
 
      print cppfile "<< $param[$i]\[$j\] << \", \" ";
 
    }
 
    print cppfile "<< $param[$i]\[$#paramlist\] << endl;\n";
 
  } else {
 
    if ($convtype[$i] eq "bool") {
 
      print cppfile "  os << \" $param[$i] = \" << sbool($param[$i]) << endl;\n";
 
    } else {
 
      if ($convtype[$i] eq "char *") {
 
	print cppfile "\n  if ($param[$i]) \n";
 
	print cppfile "  ";
 
      }
 
      print cppfile "  os << \" $param[$i] = \" << $param[$i] << endl;\n";
 
	for ($i=0;$i<$lines;$i++) {
 
	    
 
	    if ($convtype[$i] eq "label"  || $convtype[$i] eq "title") {
 
		next;
 
	    }
 
	    if ($convtype[$i] eq "double *") {
 
		print cppfile "  os << \" $param[$i] = \"";
 
		@paramlist = split(/,/,$value[$i]);
 
		for ($j=0;$j<$#paramlist;$j++) {
 
		    print cppfile "<< $param[$i]\[$j\] << \", \" ";
 
		}
 
		print cppfile "<< $param[$i]\[$#paramlist\] << endl;\n";
 
	    } else {
 
		if ($convtype[$i] eq "bool") {
 
		    print cppfile "  os << \" $param[$i] = \" << sbool($param[$i]) << endl;\n";
 
		} else {
 
		    if ($convtype[$i] eq "char *") {
 
			print cppfile "\n  if ($param[$i]) \n";
 
			print cppfile "  ";
 
		    }
 
		    print cppfile "  os << \" $param[$i] = \" << $param[$i] << endl;\n";
 
		}
 
	    }
 
    }
 
  }
 
}
 

	
 
print cppfile "}\n";
 

	
 
print cppfile <<END_TRAIL2;
 
void Parameter::XMLAdd(xmlNode *root) const {
 
  xmlNode *xmlparameter = xmlNewChild(root, NULL, BAD_CAST "parameter", NULL);
 
END_TRAIL2
 

	
 
for ($i=0;$i<$lines;$i++) {
 
  if ($convtype[$i] eq "label" || $convtype[$i] eq "title") {
 
    next;
 
  }
 
  print cppfile "{\n";
 
  print cppfile "  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST \"par\", NULL);\n";
 
  print cppfile "  xmlNewProp(xmlpar, BAD_CAST \"name\", BAD_CAST \"$param[$i]\" );\n";
 
  if ($convtype[$i] eq "double *") {
 
    @paramlist = split(/,/,$value[$i]);
 
    print cppfile "  xmlNode *xmlvalarray = xmlNewChild(xmlpar, NULL, BAD_CAST \"valarray\", NULL);\n";
 
    for ($j=0;$j<=$#paramlist;$j++) {
 
      print cppfile "  {\n";
 
      print cppfile "    ostringstream text;\n";
 
      print cppfile "    text << $param[$i]\[$j\];\n";
 
      print cppfile "    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST \"val\", NULL);\n";
 
      print cppfile "    xmlNewProp(xmlval, BAD_CAST \"v\", BAD_CAST text.str().c_str());\n";
 
      print cppfile "  }\n";
 
    }
 
    print cppfile "}\n";
 
    next;
 
} else {
 
    print cppfile "  ostringstream text;\n";
 
    if ($convtype[$i] eq "bool") {
 
      print cppfile "text << sbool($param[$i]);\n";
 
    } else {
 
      if ($convtype[$i] eq "char *") {
 
	print cppfile "\n  if ($param[$i]) \n";
 
	print cppfile "  ";
 
      }
 
      print cppfile "  text << $param[$i];\n";
 
    }
 
  }
 
  print cppfile "xmlNewProp(xmlpar, BAD_CAST \"val\", BAD_CAST text.str().c_str());\n";
 
  print cppfile "}\n";
 
}
 
print cppfile "}\n";
 

	
 
    print cppfile <<END_TRAIL2;
 
    void Parameter::XMLAdd(xmlNode *root) const {
 
	xmlNode *xmlparameter = xmlNewChild(root, NULL, BAD_CAST "parameter", NULL);
 
	END_TRAIL2
 

	
 
print cppfile "void Parameter::AssignValToPar(const char *namec, const char *valc) {\n";
 
print cppfile;
 
print cppfile "  QLocale standardlocale(QLocale::C);\n";
 
print cppfile "  bool ok;\n";
 
for ($i=0;$i<$lines;$i++) {
 
	    for ($i=0;$i<$lines;$i++) {
 
		if ($convtype[$i] eq "label" || $convtype[$i] eq "title") {
 
		    next;
 
		}
 
		print cppfile "{\n";
 
		print cppfile "  xmlNode *xmlpar = xmlNewChild(xmlparameter, NULL, BAD_CAST \"par\", NULL);\n";
 
		print cppfile "  xmlNewProp(xmlpar, BAD_CAST \"name\", BAD_CAST \"$param[$i]\" );\n";
 
		if ($convtype[$i] eq "double *") {
 
		    @paramlist = split(/,/,$value[$i]);
 
		    print cppfile "  xmlNode *xmlvalarray = xmlNewChild(xmlpar, NULL, BAD_CAST \"valarray\", NULL);\n";
 
		    for ($j=0;$j<=$#paramlist;$j++) {
 
			print cppfile "  {\n";
 
			print cppfile "    ostringstream text;\n";
 
			print cppfile "    text << $param[$i]\[$j\];\n";
 
			print cppfile "    xmlNode *xmlval = xmlNewChild(xmlvalarray, NULL, BAD_CAST \"val\", NULL);\n";
 
			print cppfile "    xmlNewProp(xmlval, BAD_CAST \"v\", BAD_CAST text.str().c_str());\n";
 
			print cppfile "  }\n";
 
		    }
 
		    print cppfile "}\n";
 
		    next;
 
		} else {
 
		    print cppfile "  ostringstream text;\n";
 
		    if ($convtype[$i] eq "bool") {
 
			print cppfile "text << sbool($param[$i]);\n";
 
		    } else {
 
			if ($convtype[$i] eq "char *") {
 
			    print cppfile "\n  if ($param[$i]) \n";
 
			    print cppfile "  ";
 
			}
 
			print cppfile "  text << $param[$i];\n";
 
		    }
 
		}
 
		print cppfile "xmlNewProp(xmlpar, BAD_CAST \"val\", BAD_CAST text.str().c_str());\n";
 
		print cppfile "}\n";
 
	}
 
	print cppfile "}\n";
 

	
 
  if ($convtype[$i] eq "label" || $convtype[$i] eq "title") {
 
    next;
 
  }
 
  if ($convtype[$i] eq "double *") {
 
    next;
 
  } else {
 
    print cppfile "if (!strcmp(namec, \"$param[$i]\")) {\n";
 
    if ($convtype[$i] eq "bool") {
 
      print cppfile "$param[$i] = strtobool(valc);\n";
 
    } else {
 
      if ($convtype[$i] eq "char *") {
 
	print cppfile "  if ($param[$i]) { free($param[$i]); }\n";
 
	print cppfile "  $param[$i]=strdup(valc);\n";
 
      } else {
 
	if ($convtype[$i] eq "int") {
 
	  print cppfile "  $param[$i] = standardlocale.toInt(valc, &ok);\n";
 
	  print cppfile "  if (!ok) { MyWarning::error(\"Read error: cannot convert string \\\"%s\\\" to integer while reading parameter '$param[$i]' from XML file.\",valc); }\n";
 
	  # print cppfile "  $param[$i] = (int)strtol(valc, 0, 10);\n";
 
	} else {
 
	  # print cppfile "  $param[$i] = strtod(valc, 0);\n";
 
	  print cppfile "  $param[$i] = standardlocale.toDouble(valc, &ok);\n";
 
	  print cppfile "  if (!ok) { MyWarning::error(\"Read error: cannot convert string \\\"%s\\\" to double while reading parameter '$param[$i]' from XML file.\",valc); }\n";
 
	print cppfile "void Parameter::AssignValToPar(const char *namec, const char *valc) {\n";
 
	print cppfile;
 
	print cppfile "  QLocale standardlocale(QLocale::C);\n";
 
	print cppfile "  bool ok;\n";
 
	for ($i=0;$i<$lines;$i++) {
 

	
 
	    if ($convtype[$i] eq "label" || $convtype[$i] eq "title") {
 
		next;
 
	    }
 
	    if ($convtype[$i] eq "double *") {
 
		next;
 
	    } else {
 
		print cppfile "if (!strcmp(namec, \"$param[$i]\")) {\n";
 
		if ($convtype[$i] eq "bool") {
 
		    print cppfile "$param[$i] = strtobool(valc);\n";
 
		} else {
 
		    if ($convtype[$i] eq "char *") {
 
			print cppfile "  if ($param[$i]) { free($param[$i]); }\n";
 
			print cppfile "  $param[$i]=strdup(valc);\n";
 
		    } else {
 
			if ($convtype[$i] eq "int") {
 
			    print cppfile "  $param[$i] = standardlocale.toInt(valc, &ok);\n";
 
			    print cppfile "  if (!ok) { MyWarning::error(\"Read error: cannot convert string \\\"%s\\\" to integer while reading parameter '$param[$i]' from XML file.\",valc); }\n";
 
			    # print cppfile "  $param[$i] = (int)strtol(valc, 0, 10);\n";
 
			} else {
 
			    # print cppfile "  $param[$i] = strtod(valc, 0);\n";
 
			    print cppfile "  $param[$i] = standardlocale.toDouble(valc, &ok);\n";
 
			    print cppfile "  if (!ok) { MyWarning::error(\"Read error: cannot convert string \\\"%s\\\" to double while reading parameter '$param[$i]' from XML file.\",valc); }\n";
 
			}
 
		    }
 
		}
 
	    }
 
	    print cppfile "}\n";
 
	}
 
      }
 
    }
 
  }
 
  print cppfile "}\n";
 
}
 
print cppfile "}\n";
 
	print cppfile "}\n";
 

	
 
print cppfile "void Parameter::AssignValArrayToPar(const char *namec, vector<double> valarray) {\n";
 
print cppfile;
 
	print cppfile "void Parameter::AssignValArrayToPar(const char *namec, vector<double> valarray) {\n";
 
	print cppfile;
 

	
 
for ($i=0;$i<$lines;$i++) {
 
	for ($i=0;$i<$lines;$i++) {
 

	
 
  if ($convtype[$i] eq "double *") {
 
    @paramlist = split(/,/,$value[$i]);
 
    print cppfile "if (!strcmp(namec, \"$param[$i]\")) {\n";
 
    print cppfile "  int i=0;\n";
 
    print cppfile "  vector<double>::const_iterator v=valarray.begin();\n";
 
    print cppfile "  while (v!=valarray.end() && i <= $#paramlist ) {\n";
 
    print cppfile "     $param[$i]\[i++\]=*(v++);\n";
 
    print cppfile "  }\n";
 
    print cppfile "}\n";
 
  }
 
}
 
print cppfile "}\n";
 
	    if ($convtype[$i] eq "double *") {
 
		@paramlist = split(/,/,$value[$i]);
 
		print cppfile "if (!strcmp(namec, \"$param[$i]\")) {\n";
 
		print cppfile "  int i=0;\n";
 
		print cppfile "  vector<double>::const_iterator v=valarray.begin();\n";
 
		print cppfile "  while (v!=valarray.end() && i <= $#paramlist ) {\n";
 
		print cppfile "     $param[$i]\[i++\]=*(v++);\n";
 
		print cppfile "  }\n";
 
		print cppfile "}\n";
 
	    }
 
	}
 
	print cppfile "}\n";
 

	
 

	
 
print cppfile <<END_TRAILER;
 
	print cppfile <<END_TRAILER;
 

	
 
/* void Parameter::XMLRead(xmlNode *root) {
 
  
 
  xmlNode *cur = root->xmlChildrenNode;
 
  while (cur!=NULL) {
 
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"parameter"))){
 
      xmlNode *par_node = cur->xmlChildrenNode;
 
      while (par_node!=NULL) {
 
	{
 
	  if (!xmlStrcmp(par_node->name, (const xmlChar *)"par")) {
 
	    xmlChar *namec = xmlGetProp(par_node, BAD_CAST "name");
 
	    xmlChar *valc = xmlGetProp(par_node, BAD_CAST "val");
 
	    if (valc) {
 
	      AssignValToPar((const char*)namec,(const char*)valc);
 
	    } else {
 
	      // Probably a valarray
 
	      xmlNode *sub_par_node = par_node->xmlChildrenNode;
 
	      vector<double> valarray; 
 
	      while (sub_par_node != NULL) {
 
		if (!xmlStrcmp(sub_par_node->name, (const xmlChar *)"valarray")) {
 
		  valarray = XMLIO::XMLReadValArray(sub_par_node);
 
	/* void Parameter::XMLRead(xmlNode *root) {
 
	    
 
	    xmlNode *cur = root->xmlChildrenNode;
 
	    while (cur!=NULL) {
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"parameter"))){
 
		    xmlNode *par_node = cur->xmlChildrenNode;
 
		    while (par_node!=NULL) {
 
			{
 
			    if (!xmlStrcmp(par_node->name, (const xmlChar *)"par")) {
 
				xmlChar *namec = xmlGetProp(par_node, BAD_CAST "name");
 
				xmlChar *valc = xmlGetProp(par_node, BAD_CAST "val");
 
				if (valc) {
 
				    AssignValToPar((const char*)namec,(const char*)valc);
 
				} else {
 
				    // Probably a valarray
 
					xmlNode *sub_par_node = par_node->xmlChildrenNode;
 
				    vector<double> valarray; 
 
				    while (sub_par_node != NULL) {
 
					if (!xmlStrcmp(sub_par_node->name, (const xmlChar *)"valarray")) {
 
					    valarray = XMLIO::XMLReadValArray(sub_par_node);
 
					}
 
					sub_par_node = sub_par_node->next;
 
				    }
 
				    AssignValArrayToPar((const char*)namec, valarray);
 
				}
 
			    }
 
			}	  
 
			par_node = par_node->next;
 
		    }
 

	
 
		}
 
		sub_par_node = sub_par_node->next;
 
	      }
 
	      AssignValArrayToPar((const char*)namec, valarray);
 
		cur=cur->next;
 
	    }
 
	  }
 
	}	  
 
	par_node = par_node->next;
 
      }
 
	    
 
	}*/
 

	
 
    }
 
    cur=cur->next;
 
  }
 
    
 
}*/
 
	    ostream &operator<<(ostream &os, Parameter &p) {
 
		p.Write(os);
 
		return os;
 
	}
 

	
 
ostream &operator<<(ostream &os, Parameter &p) {
 
  p.Write(os);
 
  return os;
 
}
 

	
 
END_TRAILER
 
	END_TRAILER
 

	
 

	
 

	
 
# parameter.h
 

	
 
open hfile, ">parameter.h";
 
print hfile <<END_HEADER2;
 
// WARNING: This file is automatically generated by make_parameter_source.pl. Do not edit.
 
// All edits will be discarded.
 
	    open hfile, ">parameter.h";
 
	print hfile <<END_HEADER2;
 
	// WARNING: This file is automatically generated by make_parameter_source.pl. Do not edit.
 
	    // All edits will be discarded.
 

	
 
#ifndef _PARAMETER_H_
 
#define _PARAMETER_H_
 
#include "vector.h"
 
#include <vector>
 

	
 
#include <libxml/parser.h>
 
#include <libxml/tree.h>
 

	
 
class Parameter {
 
  
 
 public: 
 
  Parameter();
 
  ~Parameter();
 
  void CleanUp(void);
 
  void Read(const char *filename);
 
  void Write(ostream &os) const;
 
  void XMLAdd(xmlNode *root) const;
 
  void XMLRead(xmlNode *root);
 
  void AssignValToPar(const char *namec, const char *valc);
 
  void AssignValArrayToPar(const char *namec, vector<double> valarray);
 
END_HEADER2
 
	    class Parameter {
 
		
 
	      public: 
 
		Parameter();
 
		~Parameter();
 
		void CleanUp(void);
 
		void Read(const char *filename);
 
		void Write(ostream &os) const;
 
		void XMLAdd(xmlNode *root) const;
 
		void XMLRead(xmlNode *root);
 
		void AssignValToPar(const char *namec, const char *valc);
 
		void AssignValArrayToPar(const char *namec, vector<double> valarray);
 
		END_HEADER2
 

	
 
  for ($i=0;$i<$lines;$i++) {
 
    if ($convtype[$i] ne "label" && $convtype[$i] ne "title") {
 
      print hfile "  $convtype[$i] $param[$i];\n";
 
    }
 
  }
 
		    for ($i=0;$i<$lines;$i++) {
 
			if ($convtype[$i] ne "label" && $convtype[$i] ne "title") {
 
			    print hfile "  $convtype[$i] $param[$i];\n";
 
			}
 
		}
 

	
 
print hfile <<END_TRAILER2;
 
 private:
 
};
 
		print hfile <<END_TRAILER2;
 
	      private:
 
	};
 

	
 
ostream &operator<<(ostream &os, Parameter &p);
 
const char *sbool(const bool &p);
 
	ostream &operator<<(ostream &os, Parameter &p);
 
	const char *sbool(const bool &p);
 

	
 

	
 
#endif
 
END_TRAILER2
 
	END_TRAILER2
 

	
 
# finally, a parameter file with the default values, based on the template
 

	
 
open parfile,">default.par";
 
	    open parfile,">default.par";
 

	
 
for ($i=0;$i<$lines;$i++) {
 
  if ($type[$i] ne "title" && $type[$i] ne "label") {
 
    $value[$i] =~ s/\"//g;
 
    print parfile "  $param[$i] = $value[$i]\n";
 
  }
 
}
 
	for ($i=0;$i<$lines;$i++) {
 
	    if ($type[$i] ne "title" && $type[$i] ne "label") {
 
		$value[$i] =~ s/\"//g;
 
		print parfile "  $param[$i] = $value[$i]\n";
 
	    }
 
	}
 

	
 
# finis
src/perl/make_pardialog_source.pl
Show inline comments
 
#!/usr/bin/perl 
 

	
 
#
 
# $Id$
 
#
 
#  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 <http://www.gnu.org/licenses/>.
 
#
 
#  Copyright 2010 Roeland Merks.
 
#
 

	
 
# input: parameter file + types
 
# format: par_name = default_value/type
 

	
 
# output: C++ source code of class Parameter
 
# and sample parameter file
 

	
 
%funname = (
 
	    "double" => "toDouble",
 
	    "int" => "toInt",
 
);
 
    "double" => "toDouble",
 
    "int" => "toInt",
 
    );
 

	
 
%typetrans = (
 
	      "double" => "double",
 
	      "float" => "double",
 
	      "int" => "int",
 
	      "bool" => "bool",
 
	      "char *" => "char *",
 
	      "string" => "char *",
 
	      "directory" => "char *",
 
	      "doublelist" => "double *",
 
              "label" => "label",
 
	      "title" => "title",
 
);
 
    "double" => "double",
 
    "float" => "double",
 
    "int" => "int",
 
    "bool" => "bool",
 
    "char *" => "char *",
 
    "string" => "char *",
 
    "directory" => "char *",
 
    "doublelist" => "double *",
 
    "label" => "label",
 
    "title" => "title",
 
    );
 

	
 
$basename = "pardialog";
 

	
 
open parfile,"<$ARGV[0]";
 
open cppfile,">$basename.cpp";
 

	
 
$i=0;
 
while (<parfile>) {
 
  if (/^#/) {
 
    next;
 
  }
 
  @line=split(/=/);
 
    if (/^#/) {
 
	next;
 
    }
 
    @line=split(/=/);
 
#ignore empty lines
 
  if ($#line<1) {
 
    next;
 
  }
 
  $param[$i]=$line[0];
 
  $value_type=$line[1];
 
  
 
  @typel=split(/ \/ /,$value_type);
 
  $value[$i] = $typel[0];
 
  $type[$i] = $typel[1];
 
    if ($#line<1) {
 
	next;
 
    }
 
    $param[$i]=$line[0];
 
    $value_type=$line[1];
 
    
 
    @typel=split(/ \/ /,$value_type);
 
    $value[$i] = $typel[0];
 
    $type[$i] = $typel[1];
 

	
 
  #get rid of spaces
 
  $type[$i] =~ s/ //g;
 
  $type[$i] =~s/\n//g;
 
  $convtype[$i]=$typetrans{$type[$i]};
 
  $param[$i] =~ s/ //g;
 
  if ($convtype[$i] ne "label" && $convtype[$i] ne "title") {
 
   #get rid of spaces
 
     $value[$i] =~ s/ //g;
 
  }
 
  if ($convtype[$i] eq "char *") {
 
    $value[$i] = "\"$value[$i]\"";
 
  }
 
  #print cppfile "param = $param, value = $value, type = $type\n";
 
    #get rid of spaces
 
    $type[$i] =~ s/ //g;
 
    $type[$i] =~s/\n//g;
 
    $convtype[$i]=$typetrans{$type[$i]};
 
    $param[$i] =~ s/ //g;
 
    if ($convtype[$i] ne "label" && $convtype[$i] ne "title") {
 
	#get rid of spaces
 
	$value[$i] =~ s/ //g;
 
    }
 
    if ($convtype[$i] eq "char *") {
 
	$value[$i] = "\"$value[$i]\"";
 
    }
 
    #print cppfile "param = $param, value = $value, type = $type\n";
 

	
 
  $i++;
 
    $i++;
 
}
 

	
 
$lines=$i;
 

	
 

	
 
print cppfile <<END_HEADER;
 
#include "$basename.h"
 
#include "parameter.h"
 
#include <cstring>
 
#include <qdialog.h>
 
#include <qlabel.h>
 
#include <qlineedit.h>
 
#include <qmessagebox.h>
 

	
 
ParameterDialog::ParameterDialog(QWidget *parent, const char *name, Qt::WindowFlags f) : QDialog(parent,name,false,f) {
 
  extern Parameter par;
 
END_HEADER
 
    extern Parameter par;
 
    END_HEADER
 

	
 
for ($i=0;$i<$lines;$i++) {
 
  if ($convtype[$i] eq "label" || $convtype[$i] eq "title") {
 
    next;
 
  }
 
  if ($convtype[$i] eq "double *") {
 
    print cppfile  "  QString $param[$i]_string(\"";
 
    @paramlist = split(/,/,$value[$i]);
 
    for ($j=1;$j<=$#paramlist;$j++) {
 
      print cppfile "%$j,";
 
	for ($i=0;$i<$lines;$i++) {
 
	    if ($convtype[$i] eq "label" || $convtype[$i] eq "title") {
 
		next;
 
	    }
 
	    if ($convtype[$i] eq "double *") {
 
		print cppfile  "  QString $param[$i]_string(\"";
 
		@paramlist = split(/,/,$value[$i]);
 
		for ($j=1;$j<=$#paramlist;$j++) {
 
		    print cppfile "%$j,";
 
		}
 
		print cppfile "%$j\");\n";
 
		print cppfile "  $param[$i]_string = $param[$i]_string";
 
		for ($j=0;$j<=$#paramlist;$j++) {
 
		    print cppfile ".arg(par.$param[$i]\[$j\])";
 
		}
 
		print cppfile ";\n";
 
		print cppfile "  $param[$i]_edit = new QLineEdit( $param[$i]_string, this, \"$param[$i]_edit\" );\n";
 
	    } else {
 
		if ($convtype[$i] eq "bool") {
 
		    print cppfile "  $param[$i]_edit = new QLineEdit( QString(\"%1\").arg(sbool(par.$param[$i])), this, \"$param[$i]_edit\" );\n";
 
		} else {
 
		    print cppfile "  $param[$i]_edit = new QLineEdit( QString(\"%1\").arg(par.$param[$i]), this, \"$param[$i]_edit\" );\n";
 
		}
 
	    }
 
    }
 
    print cppfile "%$j\");\n";
 
    print cppfile "  $param[$i]_string = $param[$i]_string";
 
    for ($j=0;$j<=$#paramlist;$j++) {
 
      print cppfile ".arg(par.$param[$i]\[$j\])";
 
    }
 
    print cppfile ";\n";
 
    print cppfile "  $param[$i]_edit = new QLineEdit( $param[$i]_string, this, \"$param[$i]_edit\" );\n";
 
  } else {
 
    if ($convtype[$i] eq "bool") {
 
      print cppfile "  $param[$i]_edit = new QLineEdit( QString(\"%1\").arg(sbool(par.$param[$i])), this, \"$param[$i]_edit\" );\n";
 
    } else {
 
      print cppfile "  $param[$i]_edit = new QLineEdit( QString(\"%1\").arg(par.$param[$i]), this, \"$param[$i]_edit\" );\n";
 
    }
 
  }
 
}
 

	
 

	
 
print cppfile <<END_HEADER3;
 
  // make a 1x1 grid; it will auto-expand
 
  QGridLayout *grid = new QGridLayout( this, 1, 1 );
 
  
 
  // add the first four widgets with (row, column) addressing
 
END_HEADER3
 
    print cppfile <<END_HEADER3;
 
    // make a 1x1 grid; it will auto-expand
 
	QGridLayout *grid = new QGridLayout( this, 1, 1 );
 
    
 
    // add the first four widgets with (row, column) addressing
 
	END_HEADER3
 

	
 
$numrows = 30;
 
$c = 0;
 
for ($i=0;$i<$lines;$i++) {
 
  $col = 2*int($c/($numrows-3));
 
  $row = $c % ($numrows-3) + $ntitles * 3;
 
  if ($convtype[$i] eq "label") {
 
    print cppfile "  grid->addWidget( new QLabel( \"$value[$i]\", this), $row, $col, 1, 2 );\n";
 
    $c++;
 
  } else {
 
    if ($convtype[$i] eq "title") {
 
      if ($ntitles) {
 
	print stderr "Sorry, only one title allowed. Aborting source construction...\n";
 
	exit(1);
 
      }
 
      print cppfile "  setWindowTitle( QString( \"$value[$i]\") );\n";
 
      print cppfile "  grid->addWidget( new QLabel( \"<h3>$value[$i]</h3>\",this), $row, $col, 1, -1, Qt::AlignCenter);\n";
 
      print cppfile "  grid->addWidget( new QLabel( \"\", this), $row+1, $col, 1, -1);\n";
 
      $ntitles++;
 
    } else {
 
      print cppfile "  grid->addWidget( new QLabel( \"$param[$i]\", this ),$row, $col );\n";
 
      print cppfile "  grid->addWidget( $param[$i]_edit, $row, $col+1  );\n";
 
      $c++;
 
	$numrows = 30;
 
    $c = 0;
 
    for ($i=0;$i<$lines;$i++) {
 
	$col = 2*int($c/($numrows-3));
 
	$row = $c % ($numrows-3) + $ntitles * 3;
 
	if ($convtype[$i] eq "label") {
 
	    print cppfile "  grid->addWidget( new QLabel( \"$value[$i]\", this), $row, $col, 1, 2 );\n";
 
	    $c++;
 
	} else {
 
	    if ($convtype[$i] eq "title") {
 
		if ($ntitles) {
 
		    print stderr "Sorry, only one title allowed. Aborting source construction...\n";
 
		    exit(1);
 
		}
 
		print cppfile "  setWindowTitle( QString( \"$value[$i]\") );\n";
 
		print cppfile "  grid->addWidget( new QLabel( \"<h3>$value[$i]</h3>\",this), $row, $col, 1, -1, Qt::AlignCenter);\n";
 
		print cppfile "  grid->addWidget( new QLabel( \"\", this), $row+1, $col, 1, -1);\n";
 
		$ntitles++;
 
	    } else {
 
		print cppfile "  grid->addWidget( new QLabel( \"$param[$i]\", this ),$row, $col );\n";
 
		print cppfile "  grid->addWidget( $param[$i]_edit, $row, $col+1  );\n";
 
		$c++;
 
	    }
 
	}
 
    }
 
  }
 
}
 

	
 
$row = $numrows+1;
 
$col = 2*int($i/$numrows);
 
    $row = $numrows+1;
 
    $col = 2*int($i/$numrows);
 

	
 
print cppfile <<ANOTHER_LABEL;
 
  QPushButton *pb = new QPushButton( \"&Write\", this );
 
  grid->addWidget(pb, $row, $col );
 
  connect( pb, SIGNAL( clicked() ), this, SLOT( write() ) );
 
  QPushButton *pb2 = new QPushButton( \"&Close\", this );
 
  grid->addWidget(pb2,$row, $col+1 );
 
  connect( pb2, SIGNAL( clicked() ), this, SLOT( close() ) );
 
  QPushButton *pb3 = new QPushButton( \"&Reset\", this );
 
  grid->addWidget(pb3, $row, $col+2 );
 
  connect( pb3, SIGNAL( clicked() ), this, SLOT( Reset() ) );
 
  show();
 
    print cppfile <<ANOTHER_LABEL;
 
    QPushButton *pb = new QPushButton( \"&Write\", this );
 
    grid->addWidget(pb, $row, $col );
 
    connect( pb, SIGNAL( clicked() ), this, SLOT( write() ) );
 
    QPushButton *pb2 = new QPushButton( \"&Close\", this );
 
    grid->addWidget(pb2,$row, $col+1 );
 
    connect( pb2, SIGNAL( clicked() ), this, SLOT( close() ) );
 
    QPushButton *pb3 = new QPushButton( \"&Reset\", this );
 
    grid->addWidget(pb3, $row, $col+2 );
 
    connect( pb3, SIGNAL( clicked() ), this, SLOT( Reset() ) );
 
    show();
 
};
 

	
 
ParameterDialog::~ParameterDialog(void) {
 
ANOTHER_LABEL
 
    ANOTHER_LABEL
 

	
 
for ($i=0;$i<$lines;$i++) {
 
  if ($convtype[$i] ne "label" && $convtype[$i] ne "title") {
 
    print cppfile "delete $param[$i]_edit;\n";
 
  }
 
}
 
	for ($i=0;$i<$lines;$i++) {
 
	    if ($convtype[$i] ne "label" && $convtype[$i] ne "title") {
 
		print cppfile "delete $param[$i]_edit;\n";
 
	    }
 
    }
 

	
 
print cppfile <<END_HEADER4;
 
    print cppfile <<END_HEADER4;
 
}
 

	
 
void ParameterDialog::write(void) {
 
  
 
  extern Parameter par;
 
  QString tmpval;
 
END_HEADER4
 
    
 
    extern Parameter par;
 
    QString tmpval;
 
    END_HEADER4
 

	
 
for ($i=0;$i<$lines;$i++) {
 
 if ($convtype[$i] eq "label" || $convtype[$i] eq "title") {
 
    next;
 
  }
 
 if ($convtype[$i] eq "double *") {
 
   @paramlist = split(/,/,$value[$i]);
 
   for ($j=0;$j<=$#paramlist;$j++) {
 
     print cppfile "  tmpval = $param[$i]_edit->text().section(',', $j, $j);\n";
 
     print cppfile "  par.$param[$i]\[$j\] = tmpval.toDouble();\n";
 
   }
 
 } else {
 
   if ($convtype[$i] eq "bool") {
 
     print cppfile "  tmpval = $param[$i]_edit->text().stripWhiteSpace();\n";
 
     print cppfile "  if (tmpval == \"true\" || tmpval == \"yes\" ) par.$param[$i] = true;\n";
 
     print cppfile "  else if (tmpval == \"false\" || tmpval == \"no\") par.$param[$i] = false;\n";
 
     print cppfile "  else {\n";
 
     print cppfile "    if (QMessageBox::question(this, \"Syntax error\", tr(\"Value %1 of parameter %2 is not recognized as Boolean.\\nDo you mean TRUE or FALSE?\").arg(tmpval).arg(\"$param[$i]\"),\"True\",\"False\", QString::null, 0, 1)==0) par.$param[$i]=true;\n";
 
     print cppfile "      else par.$param[$i]=false;\n";
 
     print cppfile "  }\n";
 
   } else {
 
     if ($convtype[$i] eq "char *") {
 
       print cppfile "  par.$param[$i] = strdup((const char *)$param[$i]_edit->text());\n";
 
     } else {
 
       print cppfile "  par.$param[$i] = $param[$i]_edit->text().$funname{$convtype[$i]}();\n";
 
     }
 
   }
 
 }
 
}
 
	for ($i=0;$i<$lines;$i++) {
 
	    if ($convtype[$i] eq "label" || $convtype[$i] eq "title") {
 
		next;
 
	    }
 
	    if ($convtype[$i] eq "double *") {
 
		@paramlist = split(/,/,$value[$i]);
 
		for ($j=0;$j<=$#paramlist;$j++) {
 
		    print cppfile "  tmpval = $param[$i]_edit->text().section(',', $j, $j);\n";
 
		    print cppfile "  par.$param[$i]\[$j\] = tmpval.toDouble();\n";
 
		}
 
	    } else {
 
		if ($convtype[$i] eq "bool") {
 
		    print cppfile "  tmpval = $param[$i]_edit->text().stripWhiteSpace();\n";
 
		    print cppfile "  if (tmpval == \"true\" || tmpval == \"yes\" ) par.$param[$i] = true;\n";
 
		    print cppfile "  else if (tmpval == \"false\" || tmpval == \"no\") par.$param[$i] = false;\n";
 
		    print cppfile "  else {\n";
 
		    print cppfile "    if (QMessageBox::question(this, \"Syntax error\", tr(\"Value %1 of parameter %2 is not recognized as Boolean.\\nDo you mean TRUE or FALSE?\").arg(tmpval).arg(\"$param[$i]\"),\"True\",\"False\", QString::null, 0, 1)==0) par.$param[$i]=true;\n";
 
		    print cppfile "      else par.$param[$i]=false;\n";
 
		    print cppfile "  }\n";
 
		} else {
 
		    if ($convtype[$i] eq "char *") {
 
			print cppfile "  par.$param[$i] = strdup((const char *)$param[$i]_edit->text());\n";
 
		    } else {
 
			print cppfile "  par.$param[$i] = $param[$i]_edit->text().$funname{$convtype[$i]}();\n";
 
		    }
 
		}
 
	    }
 
    }
 

	
 

	
 

	
 
print cppfile <<END_MIDPART;
 
  Reset();
 
    print cppfile <<END_MIDPART;
 
    Reset();
 

	
 
}
 
END_MIDPART
 

	
 
print cppfile "void ParameterDialog::Reset(void) {\n";
 
    print cppfile "void ParameterDialog::Reset(void) {\n";
 
print cppfile "  extern Parameter par;\n";
 

	
 
for ($i=0;$i<$lines;$i++) {
 
 if ($convtype[$i] eq "label" || $convtype[$i] eq "title") {
 
    next;
 
  }
 
  if ($convtype[$i] eq "double *") {
 
    print cppfile  "  QString $param[$i]_string(\"";
 
    @paramlist = split(/,/,$value[$i]);
 
    for ($j=1;$j<=$#paramlist;$j++) {
 
      print cppfile "%$j,";
 
    if ($convtype[$i] eq "label" || $convtype[$i] eq "title") {
 
	next;
 
    }
 
    print cppfile "%$j\");\n";
 
    print cppfile "  $param[$i]_string = $param[$i]_string";
 
    for ($j=0;$j<=$#paramlist;$j++) {
 
      print cppfile ".arg(par.$param[$i]\[$j\])";
 
    if ($convtype[$i] eq "double *") {
 
	print cppfile  "  QString $param[$i]_string(\"";
 
	@paramlist = split(/,/,$value[$i]);
 
	for ($j=1;$j<=$#paramlist;$j++) {
 
	    print cppfile "%$j,";
 
	}
 
	print cppfile "%$j\");\n";
 
	print cppfile "  $param[$i]_string = $param[$i]_string";
 
	for ($j=0;$j<=$#paramlist;$j++) {
 
	    print cppfile ".arg(par.$param[$i]\[$j\])";
 
	}
 
	print cppfile ";\n";
 
	print cppfile "  $param[$i]_edit->setText( $param[$i]_string );\n";
 
    } else {
 
	if ($convtype[$i] eq "bool") {
 
	    print cppfile "  $param[$i]_edit->setText( QString(\"%1\").arg(sbool(par.$param[$i])));\n";
 
	} else {
 
	    print cppfile "  $param[$i]_edit->setText( QString(\"%1\").arg(par.$param[$i]) );\n";
 
	}
 
    }
 
    print cppfile ";\n";
 
    print cppfile "  $param[$i]_edit->setText( $param[$i]_string );\n";
 
  } else {
 
    if ($convtype[$i] eq "bool") {
 
      print cppfile "  $param[$i]_edit->setText( QString(\"%1\").arg(sbool(par.$param[$i])));\n";
 
    } else {
 
      print cppfile "  $param[$i]_edit->setText( QString(\"%1\").arg(par.$param[$i]) );\n";
 
    }
 
  }
 
}
 

	
 
print cppfile "}\n\n";
 

	
 
# qparameter.h
 

	
 
open hfile, ">$basename.h";
 
print hfile <<END_HEADER2;
 
#ifndef PARAMETER_DIALOG_H
 
#define PARAMETER_DIALOG_H
 
#include <qdialog.h>
 
#include <qspinbox.h>
 
#include <qlineedit.h>
 
#include <qlayout.h>
 
#include <qpushbutton.h>
 
#include <iostream>
 

	
 
class ParameterDialog : public QDialog {
 
  Q_OBJECT
 
 
 
  public:
 
  ParameterDialog(QWidget *parent=0, const char *name = 0, Qt::WindowFlags f = 0);
 
  virtual ~ParameterDialog(void);
 
 public slots:
 
  void Reset(void);
 
    Q_OBJECT
 
	
 
      public:
 
	ParameterDialog(QWidget *parent=0, const char *name = 0, Qt::WindowFlags f = 0);
 
    virtual ~ParameterDialog(void);
 
    public slots:
 
    void Reset(void);
 

	
 
private slots:
 
  void write(void);
 
    private slots:
 
    void write(void);
 

	
 
 private:
 
END_HEADER2
 
  private:
 
    END_HEADER2
 

	
 
for ($i=0;$i<$lines;$i++) {
 
  if ($convtype[$i] ne "label" && $convtype[$i] ne "title") {
 
    print hfile "  QLineEdit *$param[$i]_edit;\n";
 
  }
 
}
 
	for ($i=0;$i<$lines;$i++) {
 
	    if ($convtype[$i] ne "label" && $convtype[$i] ne "title") {
 
		print hfile "  QLineEdit *$param[$i]_edit;\n";
 
	    }
 
    }
 

	
 
print hfile <<END_TRAILER2;
 
    print hfile <<END_TRAILER2;
 
};
 
#endif
 
END_TRAILER2
 

	
 
# finis
src/perl/make_xmlwritecode.pl
Show inline comments
 
#!/usr/bin/perl
 

	
 
#
 
# $Id$
 
#
 
#  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 <http://www.gnu.org/licenses/>.
 
#
 
#  Copyright 2010 Roeland Merks.
 

	
 
# Store essential model source code in XML files, so the exact model
 
# used for the geometry can be retrieved later on The crucial model
 
# description is in the files "reactions.h" (or similar) and leaf.cpp
 
# (or similar).
 

	
 
# First we should retrieve the name of the main code (i.e. leaf.cpp or
 
# so), and the version of reactions.h that we include there.
 

	
 
# We can get this from the project file (possibly called "LeafGrowth.pro")
 

	
 
# If more than one project file found, issue an error
 

	
 
open prlist, "ls *.pro |";
 

	
 
@projectfiles = ();
 
while (<prlist>) {
 
  chomp;
 
  push @projectfiles, $_;
 
    chomp;
 
    push @projectfiles, $_;
 
}
 

	
 
if ($#projectfiles > 0) {
 
  print stderr "Oops, I found several project files: ";
 
  for $p (@projectfiles) {
 
    print stderr "$p ";
 
  }
 
  print stderr "\n";
 
  print stderr "Please make sure you have only one, and try again\n";
 
  exit(1);
 
    print stderr "Oops, I found several project files: ";
 
    for $p (@projectfiles) {
 
	print stderr "$p ";
 
    }
 
    print stderr "\n";
 
    print stderr "Please make sure you have only one, and try again\n";
 
    exit(1);
 
}
 

	
 
if ($#projectfiles < 0) {
 
  print stderr "No project files found. Please add a project file.\n";
 
  exit(1);
 
    print stderr "No project files found. Please add a project file.\n";
 
    exit(1);
 
}
 

	
 
$project = $projectfiles[0];
 

	
 
print stderr "Using project file \"$project\"\n";
 

	
 
# extract TARGET and REACTIONS from project file
 

	
 
open pfile,"<$project";
 
my @targets = ();
 
while (<pfile>) {
 
  if (/^[ \t]*TARGET/) {
 
    my @line = split(/=/);
 
    my $target = $line[1];
 
    chomp $target;
 
    $target =~ s/[ \t]//g;
 
    push @targets, $target;
 
  }
 
  if (/^[ \t]*REACTIONS/) {
 
    my @line = split(/=/);
 
    my $reaction = $line[1];
 
    chomp $reaction;
 
    $reaction =~ s/[ \t]//g;
 
    push @reactions, $reaction;
 
  }
 
    if (/^[ \t]*TARGET/) {
 
	my @line = split(/=/);
 
	my $target = $line[1];
 
	chomp $target;
 
	$target =~ s/[ \t]//g;
 
	push @targets, $target;
 
    }
 
    if (/^[ \t]*REACTIONS/) {
 
	my @line = split(/=/);
 
	my $reaction = $line[1];
 
	chomp $reaction;
 
	$reaction =~ s/[ \t]//g;
 
	push @reactions, $reaction;
 
    }
 
}
 

	
 

	
 
if ($#targets > 0) {
 
  print stderr "Too many targets found: ";
 
  for $t (@targets) {
 
    print stderr "$t ";
 
  }
 
  print stderr "\n";
 
  exit(1);
 
    print stderr "Too many targets found: ";
 
    for $t (@targets) {
 
	print stderr "$t ";
 
    }
 
    print stderr "\n";
 
    exit(1);
 
}
 

	
 
if ($#targets < 0) {
 
  print stderr "No targets found in project $project\n";
 
  exit(1);
 
    print stderr "No targets found in project $project\n";
 
    exit(1);
 
}
 

	
 
$target = $targets[0];
 

	
 
print "Target is $target\n";
 

	
 
if ($#reactions > 0) {
 
  print stderr "Too many reactions found: ";
 
  for $t (@reactions) {
 
    print stderr "$t ";
 
  }
 
  print stderr "\n";
 
  exit(1);
 
    print stderr "Too many reactions found: ";
 
    for $t (@reactions) {
 
	print stderr "$t ";
 
    }
 
    print stderr "\n";
 
    exit(1);
 
}
 

	
 
if ($#reactions < 0) {
 
  print stderr "No reactions found in project $project\n";
 
  exit(1);
 
    print stderr "No reactions found in project $project\n";
 
    exit(1);
 
}
 

	
 
$reaction = $reactions[0];
 

	
 
print "Reactions header is $reaction\n";
 

	
 
$mainsource = $target.".cpp";
 

	
 
# extract "reactions" source from mainsource
 
# assuming that the header file name starts with "reactions_"
 

	
 
#open sfile, "<$mainsource";
 
#
 
#while (<sfile>) {
 
#  if (/^[ \t]*\#include/) {
 
#    chomp;
 
#    my @line = split(/\#include/);
 
#    my $header = $line[1];
 
#    $header =~ s/[\t ]//g;
 
#    if ($header =~ /reactions/) {
 
#      $header =~ s/[\"\<\>]//g;
 
#      push @headers, $header;
 
#    }
 
#  }
 
#}
 
#
 
#if ($#headers > 0) {
 
#  print stderr "Oops, more than one reactions header found: ";
 
#  for $h (@headers) {
 
#    print stderr "$h ";
 
#  }
 
#  print stderr "\n";
 
#  print stderr "Don't know what to do now... Please rename a header in $mainsource, so only one will start with \"reactions\"\n";
 
#  exit(1);
 
#}
 
#
 
#if ($#headers < 0) {
 
#  print stderr "Oops, no reactions header found in $mainsource.\n";
 
#  print stderr "Please make sure the name of your reactions header starts with \"reactions\"\n";
 
#  exit(1);
 
#}
 
#
 
#$reactions = $headers[0];
 

	
 

	
 

	
 
# now generating xmlcode to write the contents of these files (hard coded in the executables)
 

	
 
open xmlsrc, ">xmlwritecode.cpp";
 

	
 
print xmlsrc <<END_MARKER;
 
// Automatically produced by perl script \"make_xmlwritecode.pl\". DO NOT EDIT
 

	
 
#include <libxml/parser.h>
 
#include <libxml/tree.h>
 
#include <libxml/xpath.h>
 
#include <libxml/xmlreader.h>
 
#include "xmlwrite.h"
 

	
 

	
 
void XMLIO::XMLWriteLeafSourceCode(xmlNode *parent) {
 
    void XMLIO::XMLWriteLeafSourceCode(xmlNode *parent) {
 

	
 
  // Embed the code in our xml file, so we can reconstruct the model we used
 
  // to produce it... 
 
	// Embed the code in our xml file, so we can reconstruct the model we used
 
	    // to produce it... 
 

	
 
END_MARKER
 
	    END_MARKER
 

	
 
sub construct_string_constant_from_file {
 
	    sub construct_string_constant_from_file {
 

	
 
  my $fname = shift;
 
  my $str = "";
 
  
 
  open srcfile, "<$fname";
 
  while (<srcfile>) {
 
    chomp;      
 
    s/\\/\\\\/g;
 
    s/\"/\\\"/g;
 
    s/\&/\&amp;/g;
 
    $str.=$_."\\n";
 
  }
 
  $str .= "\";\n";
 
  return $str;
 
}
 
		my $fname = shift;
 
		my $str = "";
 
		
 
		open srcfile, "<$fname";
 
		while (<srcfile>) {
 
		    chomp;      
 
		    s/\\/\\\\/g;
 
		    s/\"/\\\"/g;
 
		    s/\&/\&amp;/g;
 
		    $str.=$_."\\n";
 
		}
 
		$str .= "\";\n";
 
		return $str;
 
	}
 

	
 
print xmlsrc "xmlChar *sourcecode = (xmlChar *)\"".construct_string_constant_from_file( "$mainsource" );
 
   print xmlsrc <<END_MARKER2;
 
    xmlNodePtr xmlcode = xmlNewChild(parent, NULL, BAD_CAST \"code\", sourcecode);
 
	print xmlsrc "xmlChar *sourcecode = (xmlChar *)\"".construct_string_constant_from_file( "$mainsource" );
 
	print xmlsrc <<END_MARKER2;
 
	xmlNodePtr xmlcode = xmlNewChild(parent, NULL, BAD_CAST \"code\", sourcecode);
 

	
 
     {
 
        xmlNewProp(xmlcode, BAD_CAST "name", BAD_CAST \"$mainsource\");
 
     }
 
  
 
	{
 
	    xmlNewProp(xmlcode, BAD_CAST "name", BAD_CAST \"$mainsource\");
 
	}
 
	
 
}
 

	
 
void XMLIO::XMLWriteReactionsCode(xmlNode *parent) {
 

	
 
END_MARKER2
 
    END_MARKER2
 

	
 
print xmlsrc "xmlChar *sourcecode = (xmlChar *)\"".construct_string_constant_from_file( "$reaction" );
 
   print xmlsrc <<END_MARKER3;
 
	print xmlsrc "xmlChar *sourcecode = (xmlChar *)\"".construct_string_constant_from_file( "$reaction" );
 
    print xmlsrc <<END_MARKER3;
 
    xmlNodePtr xmlcode = xmlNewChild(parent, NULL, BAD_CAST \"code\", sourcecode);
 

	
 
     {
 
    {
 
        xmlNewProp(xmlcode, BAD_CAST "name", BAD_CAST \"$reaction\");
 
     }
 
  
 
    }
 
    
 
}
 

	
 
END_MARKER3
 

	
 
# finis
src/pi.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _PI_H_
 
#define _PI_H_
 

	
 
const double Pi=3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170676;
 

	
 
#endif
 

	
 
/* finis */
src/qcanvasarrow.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _QCANVASARROW_H_
 
#define _QCANVASARROW_H_
 

	
 
#include <QGraphicsScene>
 

	
 
class QGraphicsArrowItem : public QGraphicsLineItem {
 

	
 
 public:
 
  QGraphicsArrowItem(QGraphicsItem *parent, QGraphicsScene *c) : QGraphicsLineItem(parent, c) {
 
  };
 
    
 
    void paint ( QPainter *p, const QStyleOptionGraphicsItem *option,
 
		 QWidget *widget ) {
 
 QGraphicsArrowItem(QGraphicsItem *parent, QGraphicsScene *c) : QGraphicsLineItem(parent, c) {};
 

	
 
  void paint ( QPainter *p, const QStyleOptionGraphicsItem *option,
 
	       QWidget *widget ) {
 

	
 
    widget = NULL; //use assignment merely to obviate compilation warning
 
    option = NULL;
 

	
 
      widget = NULL; //use assignment merely to obviate compilation warning
 
      option = NULL;
 
    // construct arrow head
 
    QPointF start=line().p1();
 
    QPointF end=line().p2();
 
    QPointF mid=start + (3./4.)*(end-start);
 

	
 
      // construct arrow head
 
      QPointF start=line().p1();
 
      QPointF end=line().p2();
 
      QPointF mid=start + (3./4.)*(end-start);
 
      
 
      double vx=end.x()-start.x();
 
      double vy=end.y()-start.y();
 
    double vx=end.x()-start.x();
 
    double vy=end.y()-start.y();
 

	
 
    double length = sqrt(vx*vx+vy*vy);
 
    if (length==0) return;
 

	
 
      double length = sqrt(vx*vx+vy*vy);
 
      if (length==0) return;
 
      
 
      // perpendicular vector
 
      double px=-vy/length;
 
      double py=vx/length;
 
      
 
      // Arrow head lines go from end point
 
      // to points about 3/4 of the total arrow, extending sideways about 1/4
 
      // of the arrow length.
 
      
 
      
 
      QPointF arwp1 = mid + QPointF( (int)( (length/4.)*px ),
 
    // perpendicular vector
 
    double px=-vy/length;
 
    double py=vx/length;
 

	
 
    // Arrow head lines go from end point
 
    // to points about 3/4 of the total arrow, extending sideways about 1/4
 
    // of the arrow length.
 

	
 

	
 
    QPointF arwp1 = mid + QPointF( (int)( (length/4.)*px ),
 
				   (int)( (length/4.)*py ) );
 
      QPointF arwp2 = mid - QPointF( (int)( (length/4.)*px ),
 
    QPointF arwp2 = mid - QPointF( (int)( (length/4.)*px ),
 
				   (int)( (length/4.)*py ) );
 
      
 
      p->setPen(pen());
 
      // Draw arrow head
 
      p->drawLine( end, arwp1 );
 
      p->drawLine( end, arwp2 );
 
      // Draw arrow line
 
      p->drawLine( start, end);
 
    }
 

	
 
    p->setPen(pen());
 
    // Draw arrow head
 
    p->drawLine( end, arwp1 );
 
    p->drawLine( end, arwp2 );
 
    // Draw arrow line
 
    p->drawLine( start, end);
 
  }
 
};
 

	
 
#endif
 

	
 
/* finis */
src/random.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 
 
#include <QDebug>
 
#include <string>
 
#include <stdio.h>
 
#include <stdlib.h>
 
#include <sys/timeb.h>
 
#include <iostream>
 
#include "random.h"
 
 
static const std::string _module_id("$Id$");
 
 
static int idum = -1;
 
using namespace std;
 
 
static int counter=0;
 
/*! \return A random double between 0 and 1
 
**/
 
double RANDOM(void)
 
/* Knuth's substrative method, see Numerical Recipes */
 
{
 
  static int inext,inextp;
 
  static long ma[56];
 
  static int iff=0;
 
  counter++;
 
  long mj,mk;
 
  int i,ii,k;
 
  
 
 
  if (idum < 0 || iff == 0) {
 
    iff=1;
 
    mj=MSEED-(idum < 0 ? -idum : idum);
 
    mj %= MBIG;
 
    ma[55]=mj;
 
    mk=1;
 
    i=1;
 
    do {
 
      ii=(21*i) % 55;
 
      ma[ii]=mk;
 
      mk=mj-mk;
 
      if (mk < MZ) mk += MBIG;
 
      mj=ma[ii];
 
    } while ( ++i <= 54 );
 
    k=1;
 
    do {
 
      i=1;
 
      do {
 
        ma[i] -= ma[1+(i+30) % 55];
 
        if (ma[i] < MZ) ma[i] += MBIG;
 
      } while ( ++i <= 55 );
 
    } while ( ++k <= 4 );
 
    inext=0;
 
    inextp=31;
 
    idum=1;
 
  }
 
  if (++inext == 56) inext=1;
 
  if (++inextp == 56) inextp=1;
 
  mj=ma[inext]-ma[inextp];
 
  if (mj < MZ) mj += MBIG;
 
  ma[inext]=mj;
 
  return mj*FAC;
 
}
 
 
/*! \param An integer random seed
 
  \return the random seed
 
**/
 
int Seed(int seed)
 
{
 
  if (seed < 0) {
 
    int rseed=Randomize();
 
    #ifdef QDEBUG
 
#ifdef QDEBUG
 
    qDebug() << "Randomizing random generator, seed is " << rseed << endl;
 
    #endif
 
#endif
 
    return rseed;
 
  } else {
 
    int i;
 
    idum = -seed;
 
    for (i=0; i <100; i++)
 
      RANDOM();
 
    return seed;
 
  }
 
}
 
 
 
/*! Returns a random integer value between 1 and 'max'
 
  \param The maximum value (long)
 
  \return A random integer (long)
 
**/
 
long RandomNumber(long max)
 
{
 
   return((long)(RANDOM()*max+1));
 
  return((long)(RANDOM()*max+1));
 
}
 
 
/*! Interactively ask for the seed
 
\param void
 
\return void
 
  \param void
 
  \return void
 
**/
 
void AskSeed(void)
 
{
 
  int seed;
 
  printf("Please enter a random seed: ");
 
  scanf("%d",&seed);
 
  printf("\n");
 
  Seed(seed);
 
}
 
 
int RandomCounter(void) {
 
  return counter;
 
}
 
 
/*! Make a random seed based on the local time
 
\param void
 
\return void
 
  \param void
 
  \return void
 
**/
 
 
int Randomize(void) {
 
  
 
 
  // Set the seed according to the local time
 
  struct timeb t;
 
  int seed;
 
 
  ftime(&t);
 
  
 
 
  seed=abs((int)((t.time*t.millitm)%655337));
 
  Seed(seed);
 
#ifdef QDEBUG
 
  qdebug() << "Random seed is " << seed << endl;
 
#endif
 
  return seed;
 
}
 
 
/* finis */
src/random.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _RANDOM_H_
 
#define _RANDOM_H_
 

	
 
#define MBIG 1000000000
 
#define MSEED 161803398
 
#define MZ 0
 
#define FAC (1.0/MBIG)
 

	
 
double RANDOM();
 
int Seed(int seed);
 
long RandomNumber(long max);
 
void AskSeed();
 
int Randomize(void);
 
int RandomCounter(void);
 

	
 

	
 

	
 
// Class MyUrand, so we can pass the random generator to STL's random_shuffle,
 
// and get identical simulations for a given random seed.
 
class MyUrand {
 
 
 

	
 
  long n;
 
 public:
 
  MyUrand(long nn) {
 
    n=nn;
 
  }
 
  MyUrand(void){};
 
 
 

	
 
  void seed(long s) {
 
    Seed(s);
 
  }
 
  
 

	
 
  long operator()(long nn) { return RandomNumber(nn)-1; }
 
  long operator()(void) { return RandomNumber(n); }
 
};
 

	
 

	
 

	
 
#endif
 

	
 

	
 

	
 
#endif
 
/* finis */
src/rseed.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include <iostream>
 
#include "random.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
int main() {
 

	
 
   long rseed=Randomize();
 
   std::cout << rseed << "\n";
 
  long rseed=Randomize();
 
  std::cerr << rseed << std::endl;
 
}
 

	
 
}
 
/* finis */
src/rungekutta.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include <math.h>
 
#include <iostream>
 
#include "rungekutta.h"
 
#include "warning.h"
 
#include "maxmin.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
// The value Errcon equals (5/Safety) raised to the power (1/PGrow), see use below.
 

	
 
/*
 
static float maxarg1,maxarg2;
 
#define FMAX(a,b) (maxarg1=(a),maxarg2=(b),(maxarg1) > (maxarg2) ?\
 
(maxarg1) : (maxarg2))
 
static float minarg1,minarg2;
 
#define FMIN(a,b) (minarg1=(a),minarg2=(b),(minarg1) < (minarg2) ?\
 
(minarg1) : (minarg2))
 
#define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
 
  static float maxarg1,maxarg2;
 
  #define FMAX(a,b) (maxarg1=(a),maxarg2=(b),(maxarg1) > (maxarg2) ?\
 
  (maxarg1) : (maxarg2))
 
  static float minarg1,minarg2;
 
  #define FMIN(a,b) (minarg1=(a),minarg2=(b),(minarg1) < (minarg2) ?\
 
  (minarg1) : (minarg2))
 
  #define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
 
*/
 

	
 
const double RungeKutta::Safety  = 0.9;
 
const double RungeKutta::PGrow = -0.2;
 
const double RungeKutta::Pshrnk = -0.25;
 
const double RungeKutta::Errcon = 1.89e-4;
 
const double RungeKutta::Maxstp = 10000;
 
const double RungeKutta::Tiny = 1.0e-30;
 
  
 

	
 
void RungeKutta::rkqs(double *y, double *dydx, int n, double *x, double htry, double eps,
 
			 double *yscal, double *hdid, double *hnext)
 
		      double *yscal, double *hdid, double *hnext)
 
/* Fifth-order Runge-Kutta step with monitoring of local truncation error to ensure accuracy and
 
   adjust stepsize. Input are the dependent variable vector y[1..n] and its derivative dydx[1..n]
 
   at the starting value of the independent variable x. Also input are the stepsize to be attempted
 
   htry, the required accuracy eps, and the vector yscal[1..n] against which the error is
 
   scaled. On output, y and x are replaced by their new values, hdid is the stepsize that was
 
   actuallyac complished, and hnext is the estimated next stepsize. derivs is the user-supplied
 
   routine that computes the right-hand side derivatives. */
 
{
 
  int i;
 
  double errmax,h,htemp,xnew,*yerr,*ytemp;
 
  yerr=new double[n];
 
  ytemp=new double[n];
 
  
 

	
 
  h=htry; // Set stepsize to the initial trial value.
 
  for (;;) {
 
    rkck(y,dydx,n,*x,h,ytemp,yerr); // Take a step.
 
    errmax=0.0; //Evaluate accuracy.
 
    for (i=0;i<n;i++) errmax=FMAX(errmax,fabs(yerr[i]/yscal[i]));
 
    errmax /= eps; // Scale relative to required tolerance.
 
    if (errmax <= 1.0) break; //Step succeeded. Compute size of next step.
 
    htemp=Safety*h*pow(errmax,Pshrnk);
 
    //Truncation error too large, reduce stepsize.
 
    h=(h >= 0.0 ? FMAX(htemp,0.1*h) : FMIN(htemp,0.1*h));
 
    //No more than a factor of 10.
 
    xnew=(*x)+h;
 
    if (xnew == *x) MyWarning::error("stepsize underflow in rkqs, with h = %f and htry = %f",h, htry);
 
  }
 
  if (errmax > Errcon) {
 
    *hnext=Safety*h*pow(errmax,PGrow);
 
    //std::cerr << "hnext = " << *hnext << std::endl;
 
  }
 
  else *hnext=5.0*h; //No more than a factor of 5 increase.
 
  *x += (*hdid=h);
 
  for (i=0;i<n;i++) y[i]=ytemp[i];
 
  delete[] ytemp;
 
  delete[] yerr;
 

	
 
}
 

	
 

	
 
void RungeKutta::rkck(double *y, double *dydx, int n, double x, double h, double *yout, double *yerr)
 
/*Given values for n variables y[1..n] and their derivatives dydx[1..n] known at x, use
 
  the fifth-order Cash-Karp Runge-Kutta method to advance the solution over an interval h
 
  and return the incremented variables as yout[1..n]. Also return an estimate of the local
 
  truncation error in yout using the embedded fourth-order method. The user supplies the routine
 
  derivs(x,y,dydx), which returns derivatives dydx at x.*/
 
{
 
  int i;
 

	
 
  static double a2=0.2,a3=0.3,a4=0.6,a5=1.0,a6=0.875,b21=0.2,
 
    b31=3.0/40.0,b32=9.0/40.0,b41=0.3,b42 = -0.9,b43=1.2,
 
    b51 = -11.0/54.0, b52=2.5,b53 = -70.0/27.0,b54=35.0/27.0,
 
    b61=1631.0/55296.0,b62=175.0/512.0,b63=575.0/13824.0,
 
    b64=44275.0/110592.0,b65=253.0/4096.0,c1=37.0/378.0,
 
    c3=250.0/621.0,c4=125.0/594.0,c6=512.0/1771.0,
 
    dc5 = -277.00/14336.0;
 
  double dc1=c1-2825.0/27648.0,dc3=c3-18575.0/48384.0,
 
    dc4=c4-13525.0/55296.0,dc6=c6-0.25;
 
  double *ak2,*ak3,*ak4,*ak5,*ak6,*ytemp;
 
  ak2=new double[n];
 
  ak3=new double[n];
 
  ak4=new double[n];
 
  ak5=new double[n];
 
  ak6=new double[n];
 
  ytemp=new double[n];
 
  for (i=0;i<n;i++) //First step.
 
    ytemp[i]=y[i]+b21*h*dydx[i];
 
  derivs(x+a2*h,ytemp,ak2);// Second step.
 
  for (i=0;i<n;i++)
 
    ytemp[i]=y[i]+h*(b31*dydx[i]+b32*ak2[i]);
 
  derivs(x+a3*h,ytemp,ak3); //Third step.
 
  for (i=0;i<n;i++)
 
    ytemp[i]=y[i]+h*(b41*dydx[i]+b42*ak2[i]+b43*ak3[i]);
 
  derivs(x+a4*h,ytemp,ak4); //Fourth step.
 
  for (i=0;i<n;i++)
 
    ytemp[i]=y[i]+h*(b51*dydx[i]+b52*ak2[i]+b53*ak3[i]+b54*ak4[i]);
 
  derivs(x+a5*h,ytemp,ak5); //Fifth step.
 
  for (i=0;i<n;i++)
 
    ytemp[i]=y[i]+h*(b61*dydx[i]+b62*ak2[i]+b63*ak3[i]+b64*ak4[i]+b65*ak5[i]);
 
  derivs(x+a6*h,ytemp,ak6); //Sixth step.
 
  for (i=0;i<n;i++) //Accumulate increments with proper weights.
 
    yout[i]=y[i]+h*(c1*dydx[i]+c3*ak3[i]+c4*ak4[i]+c6*ak6[i]);
 
  for (i=0;i<n;i++)
 
    yerr[i]=h*(dc1*dydx[i]+dc3*ak3[i]+dc4*ak4[i]+dc5*ak5[i]+dc6*ak6[i]);
 
  
 

	
 
  //Estimate error as difference between fourth and fifth order methods.
 
  delete[] ytemp;
 
  delete[] ak6;
 
  delete[] ak5;
 
  delete[] ak4;
 
  delete[] ak3;
 
  delete[] ak2;
 
}
 

	
 

	
 

	
 
/* User storage for intermediate results. Preset kmax and dxsav in the calling program. If kmax =
 
   0 results are stored at approximate intervals dxsav in the arrays xp[1..kount], yp[1..nvar]
 
   [1..kount], where kount is output by odeint. Defining declarations for these variables, with
 
   memoryallo cations xp[1..kmax] and yp[1..nvar][1..kmax] for the arrays, should be in
 
   the calling program.*/
 

	
 
void RungeKutta::odeint(double *ystart, int nvar, double x1, double x2, double eps, double h1, double hmin, int *nok, int *nbad)
 
/* Runge-Kutta driver with adaptive stepsize control. Integrate starting values ystart[1..nvar]
 
   from x1 to x2 with accuracy eps, storing intermediate results in global variables. h1 should
 
   be set as a guessed first stepsize, hmin as the minimum allowed stepsize (can be zero). On
 
   output nok and nbad are the number of good and bad (but retried and fixed) steps taken, and
 
   ystart is replaced byv alues at the end of the integration interval. derivs is the user-supplied
 
   routine for calculating the right-hand side derivative, while rkqs is the name of the stepper
 
   routine to be used. */
 
{
 
  int nstp,i;
 
  double xsav=0,x,hnext,hdid,h;
 
  double *yscal,*y,*dydx;
 
  yscal=new double[nvar];
 
  y=new double[nvar];
 
  dydx=new double[nvar];
 
  x=x1;
 
  h=SIGN(h1,x2-x1);
 
  *nok = (*nbad) = kount = 0;
 
  for (i=0;i<nvar;i++) y[i]=ystart[i];
 
  if (kmax > 0) xsav=x-dxsav*2.0; //Assures storage of first step.
 
  for (nstp=0;nstp<Maxstp;nstp++) { //Take at most Maxstp steps.
 
    derivs(x,y,dydx);
 
    for (i=0;i<nvar;i++)
 
      /* Scaling used to monitor accuracy. This general-purpose choice can be modified
 
	 if need be.*/
 
      yscal[i]=fabs(y[i])+fabs(dydx[i]*h)+Tiny;
 
    if (kmax > 0 && kount < kmax-1 && fabs(x-xsav) > fabs(dxsav)) {
 
      xp[kount]=x; //Store intermediate results.
 
      for (i=0;i<nvar;i++) yp[i][kount]=y[i];
 
      kount++;
 
      xsav=x;
 
    }
 
    if ((x+h-x2)*(x+h-x1) > 0.0) h=x2-x;// If stepsize can overshoot, decrease.
 
    
 

	
 
    rkqs(y,dydx,nvar,&x,h,eps,yscal,&hdid,&hnext);
 
    if (hdid == h) ++(*nok); else ++(*nbad);
 
    if ((x-x2)*(x2-x1) >= 0.0) { //Are we done?
 
      for (i=0;i<nvar;i++) ystart[i]=y[i];
 
      if (kmax) {
 
	xp[kount]=x; //Save final step.
 
	for (i=0;i<nvar;i++) yp[i][kount]=y[i];
 
      }
 
      delete[] dydx;
 
      delete[] y;
 
      delete[] yscal;
 
      return; //Normal exit.
 
    }
 
    if (fabs(hnext) <= hmin) MyWarning::error("Step size too small in odeint");
 
    h=hnext;
 
  }
 
  MyWarning::error("Too many steps in routine odeint");
 
}
 

	
 
/* finis */
src/rungekutta.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _RUNGEKUTTA_H_
 
#define _RUNGEKUTTA_H_
 

	
 
class RungeKutta  {
 

	
 
 public:
 
  RungeKutta(void) {
 
    kmax=kount=0;
 
    dxsav=0.;
 
    xp=0;
 
    yp=0;
 
  }
 
  virtual ~RungeKutta() {}
 
  
 

	
 
  void odeint(double ystart[], int nvar, double x1, double x2, double eps, double h1,
 
	      double hmin, int *nok, int *nbad);
 
  
 

	
 

	
 
 protected:
 
  // implement "derivs" in a derived class
 
  virtual void derivs(double x, double *y, double *dxdy) = 0;
 
  int kmax,kount;
 
  double *xp,**yp,dxsav;
 
  
 

	
 
 private:
 
  void rkqs(double *y, double *dydx, int n, double *x, double htry, double eps,
 
       double *yscal, double *hdid, double *hnext);
 
  
 
	    double *yscal, double *hdid, double *hnext);
 

	
 
  void rkck(double *y, double *dydx, int n, double x, double h, double yout[],
 
	    double *yerr);
 

	
 
  static const double Safety;
 
  static const double PGrow;
 
  static const double Pshrnk;
 
  static const double Errcon;
 
  static const double Maxstp;
 
  static const double Tiny;
 
  
 

	
 
};
 
#endif
 

	
 
/* finis */
src/simitembase.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include <QBrush>
 
#include "simitembase.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
SimItemBase::SimItemBase( void *v, QGraphicsScene *canvas ) {
 
SimItemBase::SimItemBase( void *v, QGraphicsScene *canvas )
 
{
 
  canvas = NULL; // use assignment merely to obviate compilation warning
 
    obj=v;
 
  obj=v;
 
};
 

	
 
SimItemBase::~SimItemBase(void) {};
 

	
 

	
 
void SimItemBase::userMove(double dx, double dy) {
 
void SimItemBase::userMove(double dx, double dy)
 
{
 
  dx = dy = 0.0; // use assignment merely to obviate compilation warning
 
};
 

	
 
/* finis */
src/simitembase.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _SIMITEMBASE_H_
 
#define _SIMITEMBASE_H_
 

	
 
#include <QGraphicsScene>
 
#include <QBrush>
 
#include <assert.h>
 
class Vector;
 

	
 

	
 
template<class TYPE> 
 
TYPE class_cast(void * symbol)
 
{
 
  assert(sizeof(void *) == sizeof(TYPE));
 
  union
 
  {
 
    void * symbol;
 
    TYPE unknownclass;
 
  } cast;
 
  
 

	
 
  cast.symbol = symbol;
 
  return cast.unknownclass;
 
}
 

	
 
class SimItemBase
 
{
 
public:
 
 public:
 
  SimItemBase( void *v, QGraphicsScene *canvas );
 
  virtual ~SimItemBase(void);
 
  virtual void userMove(double dx, double dy);
 
  
 

	
 

	
 
 protected:
 

	
 
  // I know which simulation object I represent, so if I am moved around
 
  // the canvas, the real object can be moved as well
 
  
 

	
 
  // (both Cell and Node have Vector as base class...)
 
  // Not proper design... sorry.
 
 
 

	
 
  void *obj; 
 
  };
 
};
 

	
 
#endif
 

	
 
/* finis */
src/simplugin.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include "simplugin.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
void SimPluginInterface::SetParameters(Parameter *pass_pars) {
 
	par = pass_pars; 
 
void SimPluginInterface::SetParameters(Parameter *pass_pars)
 
{
 
  par = pass_pars; 
 
}
 

	
 
void SimPluginInterface::SetCellsStaticDatamembers( CellsStaticDatamembers *cells_static_data_members_of_main)
 
{
 
	CellBase::static_data_members = cells_static_data_members_of_main;
 
  CellBase::static_data_members = cells_static_data_members_of_main;
 
}
 

	
 
/* finis */
src/simplugin.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _SIMPLUGIN_H_
 
#define _SIMPLUGIN_H_
 

	
 
#include <QtPlugin>
 
#include <QMetaType>
 
#include "cellbase.h"
 
#include "wallbase.h"
 

	
 
class Parameter;
 

	
 
#include <QColor>
 
#include <QString>
 

	
 

	
 
class SimPluginInterface {
 

	
 
public:
 
	virtual QString ModelID(void) = 0; 
 
	
 
	virtual ~SimPluginInterface() { }
 
 public:
 
  virtual QString ModelID(void) = 0; 
 

	
 
  virtual ~SimPluginInterface() { }
 

	
 
  // Executed after the cellular mechanics steps have equillibrized
 
  virtual void CellHouseKeeping(CellBase *c) = 0;
 

	
 
  // Differential equations describing transport of chemicals from cell to cell
 
  virtual void CelltoCellTransport(Wall *, double *dchem_c1, double *dchem_c2) = 0;
 

	
 
  // Differential equations describing chemical reactions taking place at or near the cell walls
 
  // (e.g. PIN accumulation)
 
  virtual void WallDynamics(Wall *w, double *dw1, double *dw)  = 0;
 

	
 
	// Executed after the cellular mechanics steps have equillibrized
 
	virtual void CellHouseKeeping(CellBase *c) = 0;
 
	
 
	// Differential equations describing transport of chemicals from cell to cell
 
	virtual void CelltoCellTransport(Wall *, double *dchem_c1, double *dchem_c2) = 0;
 
	
 
	// Differential equations describing chemical reactions taking place at or near the cell walls
 
	// (e.g. PIN accumulation)
 
	virtual void WallDynamics(Wall *w, double *dw1, double *dw)  = 0;
 
	
 
	// Differential equations describing chemical reactions inside the cells
 
	virtual void CellDynamics(CellBase *c, double *dchem) = 0;
 
  // Differential equations describing chemical reactions inside the cells
 
  virtual void CellDynamics(CellBase *c, double *dchem) = 0;
 

	
 
  // to be executed after a cell division
 
  virtual void OnDivide(ParentInfo *parent_info, CellBase *daughter1, CellBase *daughter2) = 0;
 

	
 
  // to be executed for coloring a cell
 
  virtual void SetCellColor(CellBase *c, QColor *color) = 0;
 

	
 
	// to be executed after a cell division
 
	virtual void OnDivide(ParentInfo *parent_info, CellBase *daughter1, CellBase *daughter2) = 0;
 
	
 
	// to be executed for coloring a cell
 
	virtual void SetCellColor(CellBase *c, QColor *color) = 0;
 
	
 
	// Number of chemicals
 
	virtual int NChem(void) = 0;
 
	
 
	// For internal use; not to be redefined by end users
 
	virtual void SetParameters(Parameter *pass_pars);// { par = pass_pars; }
 
	virtual void SetCellsStaticDatamembers (CellsStaticDatamembers *cells_static_data_members_of_main);
 
  // Number of chemicals
 
  virtual int NChem(void) = 0;
 

	
 
protected:
 
	class Parameter *par;
 
	
 
  // For internal use; not to be redefined by end users
 
  virtual void SetParameters(Parameter *pass_pars);// { par = pass_pars; }
 
  virtual void SetCellsStaticDatamembers (CellsStaticDatamembers *cells_static_data_members_of_main);
 

	
 
 protected:
 
  class Parameter *par;
 
};
 

	
 
Q_DECLARE_INTERFACE(SimPluginInterface, 
 
                    "nl.cwi.VirtualLeaf.SimPluginInterface/1.2") 
 
Q_DECLARE_INTERFACE(SimPluginInterface, "nl.cwi.VirtualLeaf.SimPluginInterface/1.2") 
 
Q_DECLARE_METATYPE(SimPluginInterface *)
 

	
 
#endif
 

	
 
#endif
 
\ No newline at end of file
 
/* finis */
src/sqr.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  From "Numerical recipes in C"
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#ifndef _SQR_H_
 
#define _SQR_H_
 

	
 

	
 
// redefine these macros as inline functions, to prevent scary
 
// behavior.  (According to compiler warnings, the above macros from
 
// Numerical Recipes in C are officially undefined...)
 
//
 
// However, they seem to work, but it seems safer to redefine them.
 
// Inline functions will behave like macros anyhow.
 
inline double DSQR( double a ) {
 
  
 

	
 
  if (a == 0.0) {
 
    return 0.0;
 
  } else {
 
    return a*a;
 
  }
 

	
 
}
 

	
 
inline float SQR( float a ) {
 
   if (a == 0.0) {
 
  if (a == 0.0) {
 
    return 0.0;
 
  } else {
 
    return a*a;
 
  }
 
}
 

	
 
#endif
 

	
 
/* finis */
src/tiny.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _TINY_H_
 
#define _TINY_H_
 

	
 
#define TINY 1e-5
 

	
 
#endif
 

	
 
/* finis */
src/transporterdialog.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <QtGui>
 
#include <QDoubleValidator>
 
#include <sstream>
 
#include "canvas.h"
 
#include "transporterdialog.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
TransporterDialog::TransporterDialog(Wall *w, CellBase *c, int wn, QWidget *parent)
 
  : wall(w), cell(c), wall_num(wn), QDialog(parent)
 
{
 
  int frameStyle = QFrame::Plain | QFrame::NoFrame;
 
  QPushButton *ok = new QPushButton(tr("Ok"));
 
  QPushButton *cancel = new QPushButton(tr("Cancel"));
 
  QGridLayout *t_grid = new QGridLayout; // transporter grid
 

	
 
  // connect the slots
 
  connect(ok, SIGNAL(clicked()), this, SLOT(setTransporterValues()));
 
  connect(cancel, SIGNAL(clicked()), this, SLOT(close()));
 

	
 
  // compose a label for the dialog box
 
  std::stringstream label_text; 
 
  label_text << "C("<< wall->C1()->Index() << "," << wall->C2()->Index() << "), N(" << wall->N1()->Index() << "," << wall->N2()->Index() << ")";
 
	
 
  label_text << "C("<< wall->C1()->Index() << "," << wall->C2()->Index() << "), N(" 
 
	     << wall->N1()->Index() << "," << wall->N2()->Index() << ")";
 

	
 
  // retrieve the current transporters
 
  QVector <double> transporters;  // transporter vector
 
  ntransporters = cell->NChem(); // size of transporter vector
 
  for (int i=0; i<ntransporters; ++i){
 
    transporters << ((wall_num == 1) ? wall->Transporters1(i) : wall->Transporters2(i)); // dependent on the wall number of course.
 
  }
 

	
 
  // iterate over the vector of transporter values making a label/edit line for each
 
  for (int i=0; i<transporters.size(); ++i) {
 

	
 
    // label
 
    label = new QLabel;
 
    label->setFrameStyle(frameStyle);
 
    label->setText(QString("%1").arg(i+1)); // cardinal numbering
 

	
 
    // line editor
 
    QLineEdit *editor = new QLineEdit();
 
    editors << editor;
 
    editor->setValidator(new QDoubleValidator(editor)); // validator settings
 

	
 
    // assign the current transporter value
 
    QString n;
 
    editor->setText(n.setNum(transporters[i]));
 

	
 
    // insert the label and editor into the transporter grid
 
    t_grid->addWidget(label, i, 0);
 
    t_grid->addWidget(editor, i, 1);
 
  }
 

	
 
  // add OK and Cancel buttons
 
  QGridLayout *b_grid = new QGridLayout; // button grid
 
  b_grid->addWidget(ok, 0, 0);
 
  b_grid->addWidget(cancel, 0, 1);
 

	
 
  // add both transporter and button grids to the box layout widget
 
  QVBoxLayout *layout = new QVBoxLayout;
 
  layout->addLayout(t_grid);
 
  layout->addLayout(b_grid);
 
  setLayout(layout);
 

	
 
  setWindowTitle(tr(label_text.str().c_str()));
 
}
 

	
 
void TransporterDialog::setTransporterValues(){
 

	
 
void TransporterDialog::setTransporterValues()
 
{
 
  // iterate over the editor widgets soliciting their values and setting the wall's transporters accordingly.
 
  for (int i=0; i<ntransporters; ++i){
 
    #ifdef QDEBUG  
 
#ifdef QDEBUG  
 
    qDebug() << "Transporter(" << i << "): " << editors[i]->text().toDouble() << endl;
 
    #endif
 
#endif
 
    if (wall_num == 1)
 
      wall->setTransporters1(i, editors[i]->text().toDouble());
 
    else 
 
      wall->setTransporters2(i, editors[i]->text().toDouble());
 
  }
 
  editors.resize(0);
 
  close();
 
}
 

	
 
// finis
 
/* finis */
 

	
 

	
src/transporterdialog.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _TRANSPORTERDIALOG_H_
 
#define _TRANSPORTERDIALOG_H_
 

	
 
#include <QDialog>
 
#include <QVector>
 
#include <QLineEdit>
 

	
 
class QLabel;
 
class QLineEdit;
 

	
 
class Wall;
 
class CellBase;
 

	
 
class TransporterDialog : public QDialog
 
{
 
 Q_OBJECT
 
  Q_OBJECT
 

	
 
 public:
 
  TransporterDialog(Wall *w, CellBase *c, int wn, QWidget *parent = 0);
 

	
 
 private slots:
 
  private slots:
 
  void setTransporterValues();
 

	
 
 private:
 
  Wall *wall;
 
  CellBase *cell;
 
  int wall_num;
 
  QLabel *label;
 
  int ntransporters;
 
  QVector <QLineEdit*> editors;
 
};
 

	
 
#endif
 

	
 
/* finis */
src/vector.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include <stddef.h>
 
#include <ostream>
 
#include <limits.h>
 
#include <stdio.h>
 
//#include <math.h>
 
#include <stdarg.h>
 
#include "sqr.h"
 
#include "pi.h"
 
#include "vector.h"
 
#include "tiny.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
void Vector::operator=(const Vector &source) {
 
  
 

	
 
  // assignment
 
  
 

	
 
  // don't assign to self
 
  if (this==&source) return;
 
  
 

	
 
  x=source.x;
 
  y=source.y;
 
  z=source.z;
 
  
 
}
 

	
 

	
 

	
 

	
 

	
 
ostream &Vector::print(ostream &os) const {
 
  os << "(" << x << ", " << y << ", " << z << ")";
 
  return os;
 
}
 

	
 

	
 
ostream &operator<<(ostream &os, const Vector &v) {
 
  v.print(os);
 
  return os;
 
}
 

	
 

	
 
Vector Vector::operator+(const Vector &v) const {
 
  
 

	
 
  Vector result;
 
  result.x=x+v.x;
 
  result.y=y+v.y;
 
  result.z=z+v.z;
 
  
 

	
 
  return result;
 

	
 
}
 

	
 

	
 
Vector& Vector::operator-=(const Vector &v) {
 
  
 

	
 
  x-=v.x;
 
  y-=v.y;
 
  z-=v.z;
 
  
 

	
 
  return *this;
 

	
 
}
 

	
 
Vector Vector::operator/(const double divisor) const {
 
  
 
  
 

	
 

	
 
  Vector result;
 
  
 

	
 
  result.x=x/divisor;
 
  result.y=y/divisor;
 
  result.z=z/divisor;
 

	
 
  return result;
 
  
 
  
 
}
 

	
 

	
 
Vector Vector::operator*(const double multiplier) const {
 

	
 
  Vector result;
 
  
 

	
 
  result.x=x*multiplier;
 
  result.y=y*multiplier;
 
  result.z=z*multiplier;
 

	
 
  return result;
 

	
 
  
 
}
 

	
 

	
 
Vector operator*(const double multiplier, const Vector &v) {
 

	
 
  Vector result;
 
  
 

	
 
  result.x=v.x*multiplier;
 
  result.y=v.y*multiplier;
 
  result.z=v.z*multiplier;
 

	
 
  return result;
 
  
 
}
 

	
 
Vector &Vector::operator/=(const double divisor) {
 
  x/=divisor;
 
  y/=divisor;
 
  z/=divisor;
 
  
 

	
 
  return *this;
 

	
 
}
 

	
 
Vector &Vector::operator*=(const double multiplier) {
 

	
 
  x*=multiplier;
 
  y*=multiplier;
 
  z*=multiplier;
 

	
 
  return *this;
 

	
 
}
 

	
 
Vector Vector::operator*(const Vector &v) const {
 
  
 

	
 
  // cross product ("uitproduct")
 
  Vector result;
 
  
 

	
 
  result.x=y*v.z-z*v.y;
 
  result.y=z*v.x-x*v.z;
 
  result.z=x*v.y-y*v.x;
 
  
 

	
 
  return result;
 
  
 
  
 
}
 

	
 

	
 
double InnerProduct(const Vector &v1, const Vector &v2) {
 

	
 
  // Inner product ("inproduct")
 
  double result;
 
  result=v1.x*v2.x+v1.y*v2.y+v1.z*v2.z;
 
  return result;
 

	
 
}
 

	
 
double Vector::Angle(const Vector &v) const {
 
  
 

	
 
  // angle between this vector and another vector
 
  
 

	
 
  // angle is within range of [0,pi] radians
 
  
 

	
 
  // angle is arccosine of the inner product over the product of the norms of the vectors
 
  
 

	
 
  double cos_angle=InnerProduct(*this,v)/(Norm()*v.Norm());
 
  
 

	
 
  // check for computational inaccuracies
 
  if (cos_angle<=-1)
 
    return Pi;
 
  
 

	
 
  if (cos_angle>=1)
 
    return 0.;
 
  
 

	
 
  double angle=acos(cos_angle);
 
  
 

	
 
  return angle;
 

	
 
}
 

	
 
double Vector::SignedAngle(const Vector &v) const {
 
  
 

	
 
  // angle between this vector and another vector
 
  
 

	
 
  // angle is within range of [-pi,pi] radians
 
  
 

	
 
  // angle is arccosine of the inner product over the product of the norms of the vectors
 
  
 

	
 
  double cos_angle=InnerProduct(*this,v)/(Norm()*v.Norm());
 
  
 

	
 
  // check for computational inaccuracies
 
  if (cos_angle<=-1)
 
    return Pi;
 
  
 

	
 
  if (cos_angle>=1)
 
    return 0.;
 
  
 

	
 
  double angle=acos(cos_angle);
 
  
 

	
 
  double sign = (InnerProduct ( Perp2D(), v ) )>0.?1.:-1.;
 
  return angle * sign;
 

	
 
}
 

	
 

	
 
bool Vector::operator==(const Vector &v) const {
 
   
 

	
 
  // "sloppy equal"
 
  if ((fabs(x-v.x)<TINY) && (fabs(y-v.y)<TINY) && (fabs(z-v.z)<TINY))
 
    return true;
 
  else
 
    return false;
 
  
 
}
 

	
 
bool Vector::operator< (const Vector &v) const {
 
  
 

	
 
  // Compare x coordinate
 
  if (x<v.x) 
 
    return true;
 
  else 
 
    return false;
 
  
 
}
 

	
 

	
 
double Vector::SqrNorm(void) const {
 
  
 

	
 
  // return the square of the norm
 
  // added this function to avoid taking the square root and 
 
  // the square again if this value is needed
 
  return DSQR(x)+DSQR(y)+DSQR(z);
 

	
 
}
 

	
 
void Vector::Normalise(void) {
 
  
 

	
 
  double norm;
 
  norm=Norm(); // Absolute value;
 
  
 

	
 
  if (norm>0.) { // if the norm is 0, don't normalise 
 
    // (otherwise division by zero occurs)
 
    
 

	
 
    (*this)/=norm;
 
  }
 
  
 
}
 

	
 
Vector Vector::Normalised(void) const {
 
  
 

	
 
  double norm;
 
  norm=Norm(); // Absolute value;
 
  
 

	
 
  if (norm>0.) { // if the norm is 0, don't normalise 
 
    // (otherwise division by zero occurs)
 
    return (*this)/norm;
 
  } else {
 
    return *this;
 
  }
 
    
 
}
 

	
 
bool Vector::SameDirP(const Vector &v) {
 
  
 

	
 
  // return true if the two (parallel) vectors point in the same direction
 
  //  if (x*v.x>=0 && y*v.y>=0 && z*v.z>=0)
 
  double angle=Angle(v);
 
  
 

	
 
  if (angle<(Pi/2))
 
    return true;
 
  else
 
    return false;
 
 
 
}
 

	
 
double Vector::Max(void) {
 
  
 

	
 
  // Find maximum value of vector
 
  double max;
 
  
 

	
 
  max=x > y ? x : y;
 
  max=max > z ? max : z;
 
  
 

	
 
  return max;
 
}
 

	
 
double Vector::Min(void) {
 
  
 

	
 
  // Find minimum value of vector
 
  double min;
 
  
 

	
 
  min=x < y ? x : y;
 
  min=min < z ? min : z;
 
  
 

	
 
  return min;
 
}
 

	
 
// test
 

	
 
#ifdef TEST
 

	
 
void main() {
 
  
 

	
 
  Vector v(1.,2.,3.);
 
  
 

	
 
  Vector d;
 
  
 

	
 
  d=5*v;
 
  
 
//  cerr << d << "\n";
 
  
 

	
 
  //  cerr << d << "\n";
 

	
 
  d=v*5;
 
  
 
//  cerr << d << "\n";
 
  
 

	
 
  //  cerr << d << "\n";
 

	
 
  d=v/5;
 
  
 
//  cerr << d << "\n";
 

	
 
//  cerr << d.Norm() << "\n";
 
  
 
  //  cerr << d << "\n";
 

	
 
  //  cerr << d.Norm() << "\n";
 

	
 
  d.Normalise();
 
  
 
//  cerr << d << "  " << d.Norm() << "\n";
 
  
 
  
 

	
 
  //  cerr << d << "  " << d.Norm() << "\n";
 
}
 

	
 
#endif 
 

	
 
/* finis */
src/vector.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _VECTOR_H_
 
#define _VECTOR_H_
 

	
 
#include <iostream>
 
#include <cmath>
 
#include "sqr.h"
 
#ifdef QTGRAPHICS
 
 #include <QPointF>
 
#include <QPointF>
 
#endif
 

	
 
// three dimensional vector
 
using namespace std;
 

	
 
class Vector {
 

	
 
public:
 
 public:
 
  inline Vector(const double cx=0,const double cy=0,const double cz=0) {
 
    x=cx;
 
    y=cy;
 
    z=cz;
 
  }; 
 
  explicit inline Vector(const double m[3]) {
 
    x=m[0];
 
    y=m[1];
 
    z=m[2];
 
  }
 

	
 
  // should be taken over by default arguments of Vector constructor
 
  /*  inline Vector(void) { */
 
  /*     x=0.; */
 
  /*     y=0.; */
 
  /*     z=0.; */
 
  /*   } */
 

	
 
  inline Vector(const Vector &source) { 
 
    
 

	
 
    // copy constructor
 
    
 

	
 
    x=source.x;
 
    y=source.y;
 
    z=source.z;
 
    
 

	
 
  }
 
  // type conversion from and to QPointF (2D vector class from Qt library; we throw away "z" here!!)
 
  #ifdef QTGRAPHICS
 
#ifdef QTGRAPHICS
 
  inline operator QPointF() const {
 
    return QPointF( x, y );
 
  }
 
  inline Vector(const QPointF &p) {
 
    x = p.x();
 
    y = p.y();
 
    z = 0.;
 
  }
 
  #endif
 
#endif
 
  virtual ~Vector() {
 

	
 
  };
 

	
 
  virtual ostream& print(ostream &os) const;
 
  void operator=(const Vector &source); // assignment operator
 
  void operator=(const double &s) {
 
    x=s;
 
    y=s;
 
    z=s;
 
  }
 
  Vector operator+(const Vector &v) const; // addition
 
  inline Vector operator-(const Vector &v) const { 
 
    
 

	
 
    Vector result;
 
    
 

	
 
    result.x=x-v.x;
 
    result.y=y-v.y;
 
    result.z=z-v.z;
 
    
 

	
 
    return result;
 
    
 
  }
 
  Vector &operator-=(const Vector &v);
 
  
 

	
 
  inline Vector &operator+=(const Vector &v) {
 
  
 

	
 
    x+=v.x;
 
    y+=v.y;
 
    z+=v.z;
 
    
 

	
 
    return *this;
 
    
 
  }
 
  
 

	
 
  Vector operator/(const double divisor) const; // division by a double
 
  Vector operator*(const double multiplier) const; // multiply by a scalar (double)
 
  Vector &operator/=(const double divisor);
 
  Vector &operator*=(const double multiplier);
 
  Vector operator*(const Vector &v) const; // cross product
 
  bool operator==(const Vector &v) const; // comparison
 
  bool operator< (const Vector &v) const; // order x,y,z
 
  inline double Norm(void) const {
 
  
 

	
 
    return sqrt(DSQR(x)+DSQR(y)+DSQR(z));
 
    
 
  }
 

	
 
  // Quick and dirty Norm (i.e. Manhattan distance)
 
  // (e.g. useful if we want to see if the vec is (0,0,0);
 
  inline double ManhattanNorm(void) const {
 
    return x+y+z;
 
  }
 
  
 

	
 
  double SqrNorm(void) const; // gives the square of |v|
 
  void Normalise(void); // normalise myself
 
  Vector Normalised(void) const; // return me normalised
 
  double Angle(const Vector &angle) const; // gives the angle between me and another vector
 
  double SignedAngle(const Vector &v) const;
 
  bool SameDirP(const Vector &v);
 
  double Max(void); // Find max, resp. min value of vector
 
  double Min(void);
 
  Vector Perp2D(void) const {
 
    return Vector(y,-x,0);
 
  }
 

	
 
  // data members
 
  double x,y,z;
 

	
 
  void Dump(ostream &os) const { 
 
    os << x << " " << y << " " << z << " ";
 
  }
 
  void ReadDump(istream &is) {
 
    is >> x >> y >> z;
 
  }
 
private:
 

	
 
 private:
 
};
 

	
 
ostream &operator<<(ostream &os, const Vector &v);
 
Vector operator*(const double multiplier, const Vector &v);
 
double InnerProduct(const Vector &v1, const Vector &v2);
 

	
 
#endif
 

	
 
/* finis */
src/vleafmodel.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#ifndef _VLEAFMODEL_H_
 
#define _VLEAFMODEL_H_
 

	
 
#include <QObject>
 
#include <QtGui>
 
#include <fstream>
 
#include "simplugin.h"
 

	
 
#include "parameter.h"
 

	
 
#include "wallbase.h"
 
#include "cellbase.h"
 
#include "mymodel.h"
 
#include "flux_function.h"
 

	
 
#endif
 

	
 
/* finis */
src/wall.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include "wall.h"
 
#include "cell.h"
 
#include "wallitem.h"
 
#include "node.h"
 
#include "apoplastitem.h"
 
#include <algorithm>
 
#include <QGraphicsScene>
 

	
 
static const std::string _module_id("$Id$");
 

	
 
/*! Check if this Wall still belongs to Cell a, otherwise gives it to Cell b.
 
 \return true: Wall was corrected
 
 \return false: Wall was still correct
 
 */
 
  \return true: Wall was corrected
 
  \return false: Wall was still correct
 
*/
 
bool Wall::CorrectWall( void ) {
 
	
 
	
 
	// collect all cells to which my nodes are connected on one list
 
	list<CellBase *> owners;
 
	transform(n1->owners.begin(),n1->owners.end(), back_inserter(owners), mem_fun_ref(&Neighbor::getCell));
 
	transform(n2->owners.begin(),n2->owners.end(), back_inserter(owners), mem_fun_ref(&Neighbor::getCell));
 
	
 
	// get the list of duplicates
 
	list<CellBase *> wall_owners;
 
	owners.sort();
 
	//transform(owners.begin(), owners.end(), ostream_iterator<int>(cerr, ", "), mem_fun(&Cell::Index));
 
	duplicates_copy( owners.begin(), owners.end(), back_inserter(wall_owners) );
 
	
 
	// duplicates are the cells to which the Wall belongs
 
	// For the first division, wall finds three "owners", including the boundary_polygon.
 
	// Remove that one from the list.
 
	//cerr << "wall_owners.size() = " << wall_owners.size() << endl;
 
	if (wall_owners.size() == 3 && nwalls==1 /* bug-fix 22/10/2007; confine this condition to first division only */) {
 
		
 
	        #ifdef QDEBUG
 
	        qDebug() << "nwalls = " << nwalls << endl;
 
		#endif
 
		// special case for first cleavage
 
		
 
		// find boundary polygon in the wall owners list
 
		list<CellBase *>::iterator bpit = find_if (
 
												   wall_owners.begin(), wall_owners.end(), 
 
												   mem_fun( &CellBase::BoundaryPolP )
 
												   );
 
		
 
		if (bpit!=wall_owners.end()) {
 
			
 
			// add a Wall with the boundary_polygon to each cell
 
			Wall *bp_wall1 = new Wall( n2, n1, c1, (*bpit) );
 
			bp_wall1->CopyWallContents(*this);
 
			((Cell *)c1)->AddWall( bp_wall1);
 
			((Cell *)(*bpit))->AddWall(bp_wall1);
 
			
 
			Wall *bp_wall2 = new Wall( n1, n2, c2, (*bpit) );
 
			bp_wall2->CopyWallContents(*this);
 
			((Cell *)c2)->AddWall( bp_wall2);
 
			((Cell *)(*bpit))->AddWall(bp_wall2);
 
			
 
			wall_owners.erase(bpit); 
 
			
 
		}else {
 

	
 

	
 
  // collect all cells to which my nodes are connected on one list
 
  list<CellBase *> owners;
 
  transform(n1->owners.begin(),n1->owners.end(), back_inserter(owners), mem_fun_ref(&Neighbor::getCell));
 
  transform(n2->owners.begin(),n2->owners.end(), back_inserter(owners), mem_fun_ref(&Neighbor::getCell));
 

	
 
  // get the list of duplicates
 
  list<CellBase *> wall_owners;
 
  owners.sort();
 
  //transform(owners.begin(), owners.end(), ostream_iterator<int>(cerr, ", "), mem_fun(&Cell::Index));
 
  duplicates_copy( owners.begin(), owners.end(), back_inserter(wall_owners) );
 

	
 
  // duplicates are the cells to which the Wall belongs
 
  // For the first division, wall finds three "owners", including the boundary_polygon.
 
  // Remove that one from the list.
 
  //cerr << "wall_owners.size() = " << wall_owners.size() << endl;
 
  if (wall_owners.size() == 3 && nwalls==1 /* bug-fix 22/10/2007; confine this condition to first division only */) {
 

	
 
#ifdef QDEBUG
 
    qDebug() << "nwalls = " << nwalls << endl;
 
#endif
 
    // special case for first cleavage
 

	
 
    // find boundary polygon in the wall owners list
 
    list<CellBase *>::iterator bpit = find_if (
 
					       wall_owners.begin(), wall_owners.end(), 
 
					       mem_fun( &CellBase::BoundaryPolP )
 
					       );
 
    if (bpit!=wall_owners.end()) {
 

	
 
      // add a Wall with the boundary_polygon to each cell
 
      Wall *bp_wall1 = new Wall( n2, n1, c1, (*bpit) );
 
      bp_wall1->CopyWallContents(*this);
 
      ((Cell *)c1)->AddWall( bp_wall1);
 
      ((Cell *)(*bpit))->AddWall(bp_wall1);
 

	
 
      Wall *bp_wall2 = new Wall( n1, n2, c2, (*bpit) );
 
      bp_wall2->CopyWallContents(*this);
 
      ((Cell *)c2)->AddWall( bp_wall2);
 
      ((Cell *)(*bpit))->AddWall(bp_wall2);
 

	
 
      wall_owners.erase(bpit); 
 

	
 
    }else {
 

	
 
#ifdef QDEBUG
 
      qDebug() << "Wall::CorrectWall says: Wall has three owners, but none of them is the BoundaryPolygon. I have no clue what to do with this case... Sorry!" << endl;
 
      qDebug() << "Wall: " << *this << endl;
 
      qDebug() << "Owners are: ";
 
      transform(wall_owners.begin(), wall_owners.end(), ostream_iterator<int>(qDebug(), "  "), mem_fun (&CellBase::Index) );
 
      qDebug() << endl;
 
      qDebug() << "Owners node " << n1->Index() << ": ";
 

	
 
		  #ifdef QDEBUG
 
		  qDebug() << "Wall::CorrectWall says: Wall has three owners, but none of them is the BoundaryPolygon. I have no clue what to do with this case... Sorry!" << endl;
 
		  qDebug() << "Wall: " << *this << endl;
 
		  qDebug() << "Owners are: ";
 
		  transform(wall_owners.begin(), wall_owners.end(), ostream_iterator<int>(qDebug(), "  "), mem_fun (&CellBase::Index) );
 
		  qDebug() << endl;
 
		  qDebug() << "Owners node " << n1->Index() << ": ";
 
		  for (list<Neighbor>::iterator i = n1->owners.begin(); i!=n1->owners.end(); i++) {
 
		    qDebug() << i->getCell()->Index() << " ";
 
		  }
 
		  qDebug() << endl;
 
		  qDebug() << "Owners node " << n2->Index() << ": ";
 
			
 
		  for (list<Neighbor>::iterator i = n2->owners.begin(); i!=n2->owners.end(); i++) {
 
		    qDebug() << i->getCell()->Index() << " ";
 
		  }
 
		  qDebug() << endl;
 
                  #endif
 
		  std::exit(1);
 
		}
 
		
 
	}
 
	
 
	#ifdef QDEBUG
 
	if (wall_owners.size() == 1) {
 
	  qDebug() << "Corner point. Special case." << endl;
 
	}
 
	#endif
 
	
 
	CellBase *cell1 = wall_owners.front();
 
	CellBase *cell2 = wall_owners.back();
 
	
 
	if ( (c1 == cell1 && c2==cell2) || (c1 == cell2 && c2 == cell1) ) {
 
		
 
		return false;
 
      for (list<Neighbor>::iterator i = n1->owners.begin(); i!=n1->owners.end(); i++) {
 
	qDebug() << i->getCell()->Index() << " ";
 
      }
 

	
 
      qDebug() << endl;
 
      qDebug() << "Owners node " << n2->Index() << ": ";
 

	
 
      for (list<Neighbor>::iterator i = n2->owners.begin(); i!=n2->owners.end(); i++) {
 
	qDebug() << i->getCell()->Index() << " ";
 
      }
 
      qDebug() << endl;
 
#endif
 
      std::exit(1);
 
    }
 
  }
 

	
 
#ifdef QDEBUG
 
  if (wall_owners.size() == 1) {
 
    qDebug() << "Corner point. Special case." << endl;
 
  }
 
#endif
 

	
 
  CellBase *cell1 = wall_owners.front();
 
  CellBase *cell2 = wall_owners.back();
 

	
 
  if ( (c1 == cell1 && c2==cell2) || (c1 == cell2 && c2 == cell1) ) {
 

	
 
    return false;
 
  }
 

	
 
  if ( c1 == cell1 ) {
 
    //cerr << "Block 1\n";
 
    ((Cell *)c2) -> RemoveWall(this);
 
    c2 = cell2;
 
    ((Cell *)c2) -> AddWall(this);
 
  } else {
 
    if ( c1 == cell2 ) {
 
      //	cerr << "Block 2\n";
 
      ((Cell *)c2) -> RemoveWall(this);
 
      c2 = cell1;
 
      ((Cell *)c2) -> AddWall(this);
 
    } else {
 
      if ( c2 == cell1) {
 
	((Cell *)c1)->RemoveWall(this);
 
	c1 = cell2;
 
	((Cell *)c1) -> AddWall(this);
 
	//  cerr << "Block 3\n";
 
      } else {
 
	if ( c2 == cell2) {
 
	  ((Cell *)c1)->RemoveWall(this);
 
	  c1 = cell1;
 
	  ((Cell *)c1)->AddWall(this);
 
	  //	  cerr << "Block 3\n";
 
	} else {
 
#ifdef QDEBUG
 
	  qDebug() << "Warning, cell wall was not corrected." << endl;
 
#endif
 
	  return false;
 
	}
 
	
 
	if ( c1 == cell1 ) {
 
		//cerr << "Block 1\n";
 
		((Cell *)c2) -> RemoveWall(this);
 
		c2 = cell2;
 
		((Cell *)c2) -> AddWall(this);
 
	} else {
 
		if ( c1 == cell2 ) {
 
			//	cerr << "Block 2\n";
 
			((Cell *)c2) -> RemoveWall(this);
 
			c2 = cell1;
 
			((Cell *)c2) -> AddWall(this);
 
		} else {
 
			if ( c2 == cell1) {
 
				((Cell *)c1)->RemoveWall(this);
 
				c1 = cell2;
 
				((Cell *)c1) -> AddWall(this);
 
				//  cerr << "Block 3\n";
 
			} else {
 
				if ( c2 == cell2) {
 
					((Cell *)c1)->RemoveWall(this);
 
					c1 = cell1;
 
					((Cell *)c1)->AddWall(this);
 
					//	  cerr << "Block 3\n";
 
				} else {
 
				        #ifdef QDEBUG
 
				        qDebug() << "Warning, cell wall was not corrected." << endl;
 
					#endif
 
					return false;
 
				}
 
			}
 
		}
 
	}
 
	
 
	return true;
 
	
 
	
 
	
 
	
 
      }
 
    }
 
  }
 
  return true;
 
}
 

	
 
void Wall::Draw(QGraphicsScene *c) {
 
	
 
	WallItem *wi1 = new WallItem(this, 1, c);
 
	WallItem *wi2 = new WallItem(this, 2, c);
 
	wi1->show();
 
	wi2->show();
 
	
 

	
 
  WallItem *wi1 = new WallItem(this, 1, c);
 
  WallItem *wi2 = new WallItem(this, 2, c);
 
  wi1->show();
 
  wi2->show();
 
}
 

	
 
void Wall::DrawApoplast(QGraphicsScene *c) {
 
	ApoplastItem *apo = new ApoplastItem(this, c);
 
	apo->show();
 
	
 
  ApoplastItem *apo = new ApoplastItem(this, c);
 
  apo->show();
 
}
 

	
 
void Wall::ShowStructure(QGraphicsScene *c) {
 
	
 
	Vector offset = Cell::Offset();
 
	double factor = Cell::Factor();
 
	
 
	Vector startpoint ( ((offset.x+n1->x)*factor),((offset.y+n1->y)*factor)),
 

	
 
  Vector offset = Cell::Offset();
 
  double factor = Cell::Factor();
 

	
 
  Vector startpoint ( ((offset.x+n1->x)*factor),((offset.y+n1->y)*factor)),
 
    endpoint (((offset.x+n2->x)*factor),((offset.y+n2->y)*factor));
 
	
 
	Vector linevec = endpoint - startpoint;
 
	Vector midline = startpoint + linevec/2.;
 
	Vector perpvec = linevec.Normalised().Perp2D();
 
	Vector textpos1 = midline + 100 * perpvec;
 
	Vector textpos2 = midline - 100 * perpvec;
 
    
 
	QGraphicsLineItem *line = new QGraphicsLineItem(0,c);
 
    
 
	line->setPen( QPen(QColor(par.arrowcolor),2) );
 
	line->setLine(startpoint.x, startpoint.y, endpoint.x, endpoint.y );
 
	line->setZValue(10);
 
	line->show();
 
    
 
	QGraphicsSimpleTextItem *text1 = new QGraphicsSimpleTextItem( QString("%1").arg(c2->Index()),0,c);
 
	QGraphicsSimpleTextItem *text2 = new QGraphicsSimpleTextItem( QString("%1").arg(c1->Index()),0,c);
 
    
 
	text1 -> setPos( textpos1.x, textpos1.y );
 
	text2 -> setPos( textpos2.x, textpos2.y );
 
	text1->setZValue(20); text2->setZValue(20);
 
	
 
	text1->setFont( QFont( "Helvetica", par.nodenumsize, QFont::Bold) );
 
	text2->setFont( QFont( "Helvetica", par.nodenumsize, QFont::Bold) );
 
    
 
	text1->setPen ( QColor(par.textcolor) );
 
	text2->setPen ( text1->pen() );
 
	text1->show(); text2->show();
 
	
 

	
 
  Vector linevec = endpoint - startpoint;
 
  Vector midline = startpoint + linevec/2.;
 
  Vector perpvec = linevec.Normalised().Perp2D();
 
  Vector textpos1 = midline + 100 * perpvec;
 
  Vector textpos2 = midline - 100 * perpvec;
 

	
 
  QGraphicsLineItem *line = new QGraphicsLineItem(0,c);
 

	
 
  line->setPen( QPen(QColor(par.arrowcolor),2) );
 
  line->setLine(startpoint.x, startpoint.y, endpoint.x, endpoint.y );
 
  line->setZValue(10);
 
  line->show();
 

	
 
  QGraphicsSimpleTextItem *text1 = new QGraphicsSimpleTextItem( QString("%1").arg(c2->Index()),0,c);
 
  QGraphicsSimpleTextItem *text2 = new QGraphicsSimpleTextItem( QString("%1").arg(c1->Index()),0,c);
 

	
 
  text1 -> setPos( textpos1.x, textpos1.y );
 
  text2 -> setPos( textpos2.x, textpos2.y );
 
  text1->setZValue(20); text2->setZValue(20);
 

	
 
  text1->setFont( QFont( "Helvetica", par.nodenumsize, QFont::Bold) );
 
  text2->setFont( QFont( "Helvetica", par.nodenumsize, QFont::Bold) );
 

	
 
  text1->setPen ( QColor(par.textcolor) );
 
  text2->setPen ( text1->pen() );
 
  text1->show(); text2->show();
 
}
 
string Wall::WallTypetoStr(const WallType &wt) const {
 
	
 
	if (wt == Normal) {
 
		return string("normal");
 
	}
 
	
 
	if (wt == AuxSource) {
 
		return string("aux_source");
 
	}
 
	
 
	if (wt == AuxSink) {
 
		return string("aux_sink");
 
	}
 
	
 
	return string("");
 

	
 
  if (wt == Normal) {
 
    return string("normal");
 
  }
 

	
 
  if (wt == AuxSource) {
 
    return string("aux_source");
 
  }
 

	
 
  if (wt == AuxSink) {
 
    return string("aux_sink");
 
  }
 

	
 
  return string("");
 
}
 

	
 

	
 

	
 
/* finis */
src/wall.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _WALL_H_
 
#define _WALL_H_
 

	
 
#include "wallbase.h"
 
#include <libxml/parser.h>
 
#include <libxml/tree.h>
 

	
 
#include<QGraphicsScene>
 

	
 
class Wall : public WallBase {
 

	
 
public:
 
	Wall(Node *sn1, Node *sn2, CellBase *sc1, CellBase *sc2) : WallBase(sn1, sn2, sc1, sc2) {}
 
	
 
	
 
	void XMLAdd(xmlNodePtr parent_node) const;
 
	bool CorrectWall(void);
 
 public:
 
 Wall(Node *sn1, Node *sn2, CellBase *sc1, CellBase *sc2) : WallBase(sn1, sn2, sc1, sc2) {}
 

	
 

	
 
  void XMLAdd(xmlNodePtr parent_node) const;
 
  bool CorrectWall(void);
 

	
 

	
 
	
 
	// Graphics:
 
	//! Visualize transport protein concentrations
 
	void Draw(QGraphicsScene *c);
 
	
 
	//! Visualize contents of the apoplast
 
	void DrawApoplast(QGraphicsScene *c); 
 
	/*! \brief Visualize the structure of the wall (Cell ID's etc.). 
 
	 Used for debugging purposes.
 
	 */
 
	void ShowStructure(QGraphicsScene *c);
 
  // Graphics:
 
  //! Visualize transport protein concentrations
 
  void Draw(QGraphicsScene *c);
 

	
 
private:
 
	string WallTypetoStr(const WallType &wt) const;
 
	    
 
	
 
	
 
	
 
  //! Visualize contents of the apoplast
 
  void DrawApoplast(QGraphicsScene *c); 
 
  /*! \brief Visualize the structure of the wall (Cell ID's etc.). 
 
    Used for debugging purposes.
 
  */
 
  void ShowStructure(QGraphicsScene *c);
 

	
 
 private:
 
  string WallTypetoStr(const WallType &wt) const;
 
};
 

	
 
#endif
 

	
 
/* finis */
src/wallbase.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <QDebug>
 

	
 
#include "wall.h"
 
#include "wallbase.h"
 
#include "node.h"
 
#include "mesh.h"
 
#include "parameter.h"
 
#include <sstream>
 
#include <string>
 
#include "warning.h"
 

	
 
#ifdef QTGRAPHICS
 
#include <QGraphicsScene>
 
#include <QGraphicsLineItem>
 
#include "wallitem.h"
 
#include "apoplastitem.h"
 
#endif
 

	
 
static const std::string _module_id("$Id$");
 

	
 
int WallBase::nwalls=0;
 

	
 
ostream &WallBase::print(ostream &os) const {
 
	os << "{ " << n1->Index() << "->" << n2->Index() 
 
	<< ", " << c1->Index() << " | " << c2->Index() << "} ";
 
	return os;
 
  os << "{ " << n1->Index() << "->" << n2->Index() 
 
     << ", " << c1->Index() << " | " << c2->Index() << "} ";
 
  return os;
 
}
 

	
 
ostream &operator<<(ostream &os, const WallBase &w) { 
 
	w.print(os); 
 
	return os;
 
  w.print(os); 
 
  return os;
 
}
 

	
 

	
 
WallBase::WallBase(Node *sn1, Node *sn2, CellBase *sc1, CellBase *sc2) {
 
	
 
        #ifdef QDEBUG
 
	if (sc1==sc2) { 
 
	  qDebug() << "Attempting to build a wall between identical cells: " << sc1->Index() << endl; 
 
	}
 
	#endif
 
	
 
	c1 = sc1;
 
	c2 = sc2;
 
	
 
	n1 = sn1;
 
	n2 = sn2;
 
	
 
	transporters1 = new double[CellBase::NChem()];
 
	transporters2 = new double[CellBase::NChem()];
 
	new_transporters1 = new double[CellBase::NChem()];
 
	new_transporters2 = new double[CellBase::NChem()];
 
	
 
	for (int i=0;i<CellBase::NChem();i++) {
 
		transporters1[i] = transporters2[i] = new_transporters1[i] = new_transporters2[i] = 0.;
 
	}
 
	
 
	apoplast = new double[CellBase::NChem()]; // not yet in use.
 
    
 
	SetLength();
 
	
 
	// to visualize flux through WallBase
 
	viz_flux=0;
 
	dead = false;
 
	wall_type = Normal;
 
	wall_index = nwalls++;
 
	
 
WallBase::WallBase(Node *sn1, Node *sn2, CellBase *sc1, CellBase *sc2)
 
{
 

	
 
#ifdef QDEBUG
 
  if (sc1==sc2) { 
 
    qDebug() << "Attempting to build a wall between identical cells: " << sc1->Index() << endl; 
 
  }
 
#endif
 

	
 
  c1 = sc1;
 
  c2 = sc2;
 

	
 
  n1 = sn1;
 
  n2 = sn2;
 

	
 
  transporters1 = new double[CellBase::NChem()];
 
  transporters2 = new double[CellBase::NChem()];
 
  new_transporters1 = new double[CellBase::NChem()];
 
  new_transporters2 = new double[CellBase::NChem()];
 

	
 
  for (int i=0;i<CellBase::NChem();i++) {
 
    transporters1[i] = transporters2[i] = new_transporters1[i] = new_transporters2[i] = 0.;
 
  }
 

	
 
  apoplast = new double[CellBase::NChem()]; // not yet in use.
 

	
 
  SetLength();
 

	
 
  // to visualize flux through WallBase
 
  viz_flux=0;
 
  dead = false;
 
  wall_type = Normal;
 
  wall_index = nwalls++;
 
}
 

	
 
void WallBase::CopyWallContents(const WallBase &src) {
 
	
 
	for (int i=0; i<CellBase::NChem(); i++) {
 
		if (transporters1) {
 
			transporters1[i]=src.transporters1[i];
 
		}
 
		if (transporters2) {
 
			transporters2[i]=src.transporters2[i];
 
		}
 
		if (new_transporters1) {
 
			new_transporters1[i]=src.new_transporters1[i];
 
		}
 
		if (new_transporters2) {
 
			new_transporters2[i]=src.new_transporters2[i];
 
		}
 
		
 
		if (apoplast) {
 
			apoplast[i]=src.apoplast[i];
 
		}
 
	}
 
	dead = src.dead;
 
	wall_type = src.wall_type;
 
void WallBase::CopyWallContents(const WallBase &src)
 
{
 

	
 
  for (int i=0; i<CellBase::NChem(); i++) {
 
    if (transporters1) {
 
      transporters1[i]=src.transporters1[i];
 
    }
 
    if (transporters2) {
 
      transporters2[i]=src.transporters2[i];
 
    }
 
    if (new_transporters1) {
 
      new_transporters1[i]=src.new_transporters1[i];
 
    }
 
    if (new_transporters2) {
 
      new_transporters2[i]=src.new_transporters2[i];
 
    }
 

	
 
    if (apoplast) {
 
      apoplast[i]=src.apoplast[i];
 
    }
 
  }
 
  dead = src.dead;
 
  wall_type = src.wall_type;
 
}
 

	
 
void WallBase::SwapWallContents(WallBase *src) {
 
	
 
	for (int i=0; i<CellBase::NChem(); i++) {
 
		if (transporters1) {
 
			double tmp;
 
			
 
			tmp=src->transporters1[i];
 
			src->transporters1[i]=transporters1[i];
 
			transporters1[i]=tmp;
 
			
 
		}
 
		if (transporters2) {
 
			double tmp;
 
			tmp=src->transporters2[i];
 
			src->transporters2[i]=transporters2[i];
 
			transporters2[i]=tmp;
 
		}
 
		if (new_transporters1) {
 
			double tmp;
 
			tmp=src->new_transporters1[i];
 
			src->new_transporters1[i]=new_transporters1[i];
 
			new_transporters1[i]=tmp;
 
		}
 
		if (new_transporters2) {
 
			double tmp;
 
			tmp=src->new_transporters2[i];
 
			src->new_transporters2[i]=new_transporters2[i];
 
			new_transporters2[i]=tmp;			
 
		}
 
		
 
		if (apoplast) {
 
			double tmp;
 
			tmp=src->apoplast[i];
 
			src->apoplast[i]=apoplast[i];
 
			apoplast[i]=tmp;		
 
		}
 
	}
 
	bool tmp_bool;
 
	tmp_bool = src->dead;
 
	src->dead=dead;
 
	dead = tmp_bool;
 
	
 
	WallType tmp_wall_type;
 
	tmp_wall_type = src->wall_type;
 
	src->wall_type = wall_type;
 
	wall_type = tmp_wall_type;
 
	
 
void WallBase::SwapWallContents(WallBase *src)
 
{
 

	
 
  for (int i=0; i<CellBase::NChem(); i++) {
 
    if (transporters1) {
 
      double tmp;
 

	
 
      tmp=src->transporters1[i];
 
      src->transporters1[i]=transporters1[i];
 
      transporters1[i]=tmp;
 

	
 
    }
 
    if (transporters2) {
 
      double tmp;
 
      tmp=src->transporters2[i];
 
      src->transporters2[i]=transporters2[i];
 
      transporters2[i]=tmp;
 
    }
 
    if (new_transporters1) {
 
      double tmp;
 
      tmp=src->new_transporters1[i];
 
      src->new_transporters1[i]=new_transporters1[i];
 
      new_transporters1[i]=tmp;
 
    }
 
    if (new_transporters2) {
 
      double tmp;
 
      tmp=src->new_transporters2[i];
 
      src->new_transporters2[i]=new_transporters2[i];
 
      new_transporters2[i]=tmp;			
 
    }
 

	
 
    if (apoplast) {
 
      double tmp;
 
      tmp=src->apoplast[i];
 
      src->apoplast[i]=apoplast[i];
 
      apoplast[i]=tmp;		
 
    }
 
  }
 
  bool tmp_bool;
 
  tmp_bool = src->dead;
 
  src->dead=dead;
 
  dead = tmp_bool;
 

	
 
  WallType tmp_wall_type;
 
  tmp_wall_type = src->wall_type;
 
  src->wall_type = wall_type;
 
  wall_type = tmp_wall_type;
 
}
 

	
 
bool WallBase::SAM_P(void) { 
 
	
 
	return N1()->sam || N2()->sam; 
 
	
 
bool WallBase::SAM_P(void)
 
{ 
 
  return N1()->sam || N2()->sam; 
 
}  
 

	
 
#include <fstream>
 

	
 
void WallBase::SetLength(void) {
 
	
 
	//static bool show_nodes = true;
 
	
 
	//double old_length = length;
 
	// Step 1: find the path of nodes leading along the WallBase.
 
	// A WallBase often represents a curved cell wall: we want the total
 
	// length _along_ the wall here...
 
	
 
	// Locate first and second nodes of the edge in Cell's list of nodes
 
	list<Node *>::const_iterator first_node_edge = find(c1->nodes.begin(), c1->nodes.end(), n1);
 
	list<Node *>::const_iterator second_node_edge_plus_1 = ++find(c1->nodes.begin(), c1->nodes.end(), n2);
 
	
 
	// wrap around
 
	if (second_node_edge_plus_1 == c1->nodes.end()) {
 
		second_node_edge_plus_1 = c1->nodes.begin();
 
	}
 
	
 
	
 
	length = 0.;
 
    
 
	// Now, walk to the second node of the edge in the list of nodes
 
	stringstream deb_str;
 
	
 
	for (list<Node *>::const_iterator n=
 
		 (++first_node_edge==c1->nodes.end()?c1->nodes.begin():first_node_edge);
 
		 n!=second_node_edge_plus_1;
 
		 (++n == c1->nodes.end()) ? (n=c1->nodes.begin()):n  ) {
 
		
 
		list<Node *>::const_iterator prev_n = n; 
 
		if (prev_n==c1->nodes.begin()) prev_n=c1->nodes.end();
 
		--prev_n;
 
		
 
		//cerr << "Node: " << (Vector)(**n) << endl;
 
		
 
		// Note that Node derives from a Vector, so we can do vector calculus as defined in vector.h 
 
		
 
		
 
		deb_str << "[ " << (*prev_n)->index << " to " << (*n)->index << "]";
 
		
 
		length += (*(*prev_n) - *(*n)).Norm(); 
 
		
 
	}
 
void WallBase::SetLength(void)
 
{
 

	
 
  // Step 1: find the path of nodes leading along the WallBase.
 
  // A WallBase often represents a curved cell wall: we want the total
 
  // length _along_ the wall here...
 

	
 
  // Locate first and second nodes of the edge in Cell's list of nodes
 
  list<Node *>::const_iterator first_node_edge = find(c1->nodes.begin(), c1->nodes.end(), n1);
 
  list<Node *>::const_iterator second_node_edge_plus_1 = ++find(c1->nodes.begin(), c1->nodes.end(), n2);
 

	
 
  // wrap around
 
  if (second_node_edge_plus_1 == c1->nodes.end()) {
 
    second_node_edge_plus_1 = c1->nodes.begin();
 
  }
 

	
 

	
 
  length = 0.;
 

	
 
  // Now, walk to the second node of the edge in the list of nodes
 
  stringstream deb_str;
 

	
 
  for (list<Node *>::const_iterator n=
 
	 (++first_node_edge==c1->nodes.end()?c1->nodes.begin():first_node_edge);
 
       n!=second_node_edge_plus_1;
 
       (++n == c1->nodes.end()) ? (n=c1->nodes.begin()):n  ) {
 

	
 
    list<Node *>::const_iterator prev_n = n; 
 
    if (prev_n==c1->nodes.begin()) prev_n=c1->nodes.end();
 
    --prev_n;
 

	
 
    //cerr << "Node: " << (Vector)(**n) << endl;
 

	
 
    // Note that Node derives from a Vector, so we can do vector calculus as defined in vector.h 
 

	
 
    deb_str << "[ " << (*prev_n)->index << " to " << (*n)->index << "]";
 
    length += (*(*prev_n) - *(*n)).Norm(); 
 
  }
 
}
 

	
 
void WallBase::CorrectTransporters(double orig_length) {
 
	
 
	double length_factor = length / orig_length;
 
void WallBase::CorrectTransporters(double orig_length)
 
{
 

	
 
  double length_factor = length / orig_length;
 

	
 
	for (int ch=0;ch<CellBase::NChem();ch++) {
 
		transporters1[ch] *= length_factor;
 
		transporters2[ch] *= length_factor;
 
		new_transporters1[ch] *= length_factor;
 
		new_transporters2[ch] *= length_factor;
 
	}
 
	
 
  for (int ch=0;ch<CellBase::NChem();ch++) {
 
    transporters1[ch] *= length_factor;
 
    transporters2[ch] *= length_factor;
 
    new_transporters1[ch] *= length_factor;
 
    new_transporters2[ch] *= length_factor;
 
  }
 
}
 

	
 

	
 
Vector WallBase::VizFlux(void) {
 
	return viz_flux * ( (*n2) - (*n1) ).Normalised().Perp2D();    
 
Vector WallBase::VizFlux(void)
 
{
 
  return viz_flux * ( (*n2) - (*n1) ).Normalised().Perp2D();    
 
}
 

	
 

	
 
void WallBase::SetTransToNewTrans( void ){ 
 
	for (int i=0;i<CellBase::NChem();i++) { 
 
		transporters1[i] = new_transporters1[i]; 
 
		transporters2[i] = new_transporters2[i]; 
 
	} 
 
  for (int i=0;i<CellBase::NChem();i++) { 
 
    transporters1[i] = new_transporters1[i]; 
 
    transporters2[i] = new_transporters2[i]; 
 
  } 
 
}
 

	
 

	
 
Vector WallBase::getWallVector(CellBase *c) {
 
	if ( c == c1 ) {
 
		return ( Vector(*n2) - Vector(*n1) );
 
	} else {
 
		return ( Vector(*n1) - Vector(*n2) );
 
	}
 
	
 
Vector WallBase::getWallVector(CellBase *c)
 
{
 
  if ( c == c1 ) {
 
    return ( Vector(*n2) - Vector(*n1) );
 
  } else {
 
    return ( Vector(*n1) - Vector(*n2) );
 
  }
 
}
 
Vector WallBase::getInfluxVector(CellBase *c) {
 
	if ( c == c1 ) {
 
		return ( Vector(*n2) - Vector(*n1) ).Normalised().Perp2D();
 
	} else {
 
		return ( Vector(*n1) - Vector(*n2) ).Normalised().Perp2D();
 
	}
 
Vector WallBase::getInfluxVector(CellBase *c)
 
{
 
  if ( c == c1 ) {
 
    return ( Vector(*n2) - Vector(*n1) ).Normalised().Perp2D();
 
  } else {
 
    return ( Vector(*n1) - Vector(*n2) ).Normalised().Perp2D();
 
  }
 
}
 

	
 
//! \brief Test if this wall intersects with division plane p1 -> p2 
 
bool WallBase::IntersectsWithDivisionPlaneP(const Vector &p1, const Vector &p2) {
 
	
 
	// Algorithm of http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
 
	double x1 = n1->x, y1 = n1->y;
 
	double x2 = n2->x, y2 = n2->y;
 
	double x3 = p1.x, y3 = p1.y;
 
	double x4 = p2.x, y4 = p2.y;
 
	
 
	double ua = ( (x4 - x3) * (y1-y3) - (y4 - y3)*(x1-x3) ) / ( (y4 -y3) * (x2 -x1) - (x4-x3)*(y2-y1));
 
	
 
	// If ua is between 0 and 1, line p1 intersects the line segment
 
	if ( ua >=0. && ua <=1.) return true;
 
	else return false;
 
	
 
bool WallBase::IntersectsWithDivisionPlaneP(const Vector &p1, const Vector &p2)
 
{
 

	
 
  // Algorithm of http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
 
  double x1 = n1->x, y1 = n1->y;
 
  double x2 = n2->x, y2 = n2->y;
 
  double x3 = p1.x, y3 = p1.y;
 
  double x4 = p2.x, y4 = p2.y;
 

	
 
  double ua = ( (x4 - x3) * (y1-y3) - (y4 - y3)*(x1-x3) ) / ( (y4 -y3) * (x2 -x1) - (x4-x3)*(y2-y1));
 

	
 
  // If ua is between 0 and 1, line p1 intersects the line segment
 
  if ( ua >=0. && ua <=1.) return true;
 
  else return false;
 
}
 

	
 
/* finis */
src/wallbase.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 

	
 
#ifndef _WALLBASE_H_
 
#define _WALLBASE_H_
 

	
 
#include <list>
 
#include <iostream>
 

	
 

	
 

	
 
#include "vector.h"
 

	
 

	
 
class Node;
 
class CellBase;
 

	
 
using namespace std;
 

	
 
// warning, touches original sequence
 
template<class In, class Out> Out duplicates_copy(In first, In last, Out res) {
 
	
 
	In i = adjacent_find(first, last);
 
	
 
	while (i!=last) {
 
		res++ = *i;
 
		i = adjacent_find(++i, last);
 
	}
 
	
 
	return res;
 

	
 
  In i = adjacent_find(first, last);
 

	
 
  while (i!=last) {
 
    res++ = *i;
 
    i = adjacent_find(++i, last);
 
  }
 

	
 
  return res;
 
}
 

	
 
/*! \class WallBase. A cell wall, which runs between cell "corner points",
 
 and consists of wall elements. */
 
  and consists of wall elements. */
 
class WallBase {
 
	
 
protected:
 
	friend class CellBase;
 
	friend class Cell;
 
	friend class Mesh;
 
	//! Cells to which the wall belongs
 
	CellBase *c1, *c2;
 
	
 
	//! A list of transporter protein concentrations associated with the wall
 
	double *transporters1, *transporters2;
 
	double *new_transporters1, *new_transporters2;
 
	
 
	bool IllegalP(void) { return c1 == c2; }
 
	
 
	//! The chemicals in the apoplast at this position
 
	double *apoplast;
 
	
 
	//! Pointers to the wall's corner nodes 
 
	Node *n1, *n2;
 
	
 
	double length;
 
	
 
	double viz_flux;
 
	
 
	//  bool aux_source;
 
	
 
	bool dead;
 
		// disallow usage of empty constructor
 
	WallBase(void) {}
 
	
 
		
 
	enum WallType {Normal, AuxSource, AuxSink};
 
	static int nwalls;
 
protected:
 
	int wall_index;
 
	WallType wall_type;
 
	
 

	
 
 protected:
 
  friend class CellBase;
 
  friend class Cell;
 
  friend class Mesh;
 
  //! Cells to which the wall belongs
 
  CellBase *c1, *c2;
 

	
 
  //! A list of transporter protein concentrations associated with the wall
 
  double *transporters1, *transporters2;
 
  double *new_transporters1, *new_transporters2;
 

	
 
  bool IllegalP(void) { return c1 == c2; }
 

	
 
  //! The chemicals in the apoplast at this position
 
  double *apoplast;
 

	
 
  //! Pointers to the wall's corner nodes 
 
  Node *n1, *n2;
 

	
 
  double length;
 

	
 
  double viz_flux;
 

	
 
  //  bool aux_source;
 

	
 
  bool dead;
 
  // disallow usage of empty constructor
 
  WallBase(void) {}
 

	
 

	
 
  enum WallType {Normal, AuxSource, AuxSink};
 
  static int nwalls;
 
 protected:
 
  int wall_index;
 
  WallType wall_type;
 

	
 

	
 
 public:
 
  WallBase(Node *sn1, Node *sn2, CellBase *sc1, CellBase *sc2); 
 

	
 
public:
 
	WallBase(Node *sn1, Node *sn2, CellBase *sc1, CellBase *sc2); 
 
	
 
	// shallow copy
 
	WallBase(const WallBase &src) {
 
		c1 = src.c1;
 
		c2 = src.c2;
 
		transporters1 = src.transporters1;
 
		transporters2 = src.transporters2;
 
		new_transporters1 = src.new_transporters1;
 
		new_transporters2 = src.new_transporters2;
 
		apoplast = src.apoplast;
 
		n1 = src.n1;
 
		n2 = src.n2;
 
		length = src.length;
 
		viz_flux = src.viz_flux;
 
		dead = src.dead;
 
			wall_index = src.wall_index;
 
	}
 
	
 
	inline int Index(void) const { return wall_index;}
 
	inline bool DeadP(void) const { return dead; }
 
	inline void Kill(void) { dead = true; }
 
	// deep copying of chemicals and transporters
 
	void CopyWallContents(const WallBase &src);
 
	void SwapWallContents(WallBase *src);
 
	bool is_wall_of_cell_p ( const CellBase *c ) {
 
		return (c1==c || c2==c);
 
  // shallow copy
 
  WallBase(const WallBase &src) {
 
    c1 = src.c1;
 
    c2 = src.c2;
 
    transporters1 = src.transporters1;
 
    transporters2 = src.transporters2;
 
    new_transporters1 = src.new_transporters1;
 
    new_transporters2 = src.new_transporters2;
 
    apoplast = src.apoplast;
 
    n1 = src.n1;
 
    n2 = src.n2;
 
    length = src.length;
 
    viz_flux = src.viz_flux;
 
    dead = src.dead;
 
    wall_index = src.wall_index;
 
  }
 

	
 
  inline int Index(void) const { return wall_index;}
 
  inline bool DeadP(void) const { return dead; }
 
  inline void Kill(void) { dead = true; }
 
  // deep copying of chemicals and transporters
 
  void CopyWallContents(const WallBase &src);
 
  void SwapWallContents(WallBase *src);
 
  bool is_wall_of_cell_p ( const CellBase *c ) {
 
    return (c1==c || c2==c);
 
  }
 

	
 
  inline CellBase *C1(void) const { return c1; }
 
  inline CellBase *C2(void) const { return c2; }
 
  inline Node *N1(void) const { return n1; }
 
  inline Node *N2(void) const { return n2; }
 
  inline void setTransporters1(int ch, double val) { transporters1[ch]=val; }
 
  inline void setTransporters2(int ch, double val) { transporters2[ch]=val; }
 
  inline void setNewTransporters1(int ch, double val) { new_transporters1[ch]=val; }
 
  inline void setNewTransporters2(int ch, double val) { new_transporters2[ch]=val; }
 
  inline double Transporters1(int ch) { return transporters1[ch]; }
 
  inline double Transporters2(int ch) { return transporters2[ch]; }
 

	
 
  //! Return true if the WallBase adheres to the SAM (shoot apical meristem)
 
  bool SAM_P(void);
 
  // NB. Not checked. If cell is not found, it returns transporters2[ch]!!
 
  //inline double getTransporter(int ch, Cell *c) { return c1 == c ? transporters1[ch] : transporters2[ch]; }
 

	
 
  //! Return true if the WallBase is a source of auxin
 
  inline bool AuxinSource(void) const { return wall_type == AuxSource; }
 
  inline bool AuxinSink(void) const { return wall_type == AuxSink; }
 

	
 
  inline void cycleWallType(void) { 
 

	
 
    if (wall_type == Normal)  
 
      wall_type = AuxSource;
 
    else
 
      if (wall_type == AuxSource) 
 
	wall_type = AuxSink;
 
      else
 
	if (wall_type == AuxSink) {
 
	  wall_type = Normal;
 
	}
 
	
 
	inline CellBase *C1(void) const { return c1; }
 
	inline CellBase *C2(void) const { return c2; }
 
	inline Node *N1(void) const { return n1; }
 
	inline Node *N2(void) const { return n2; }
 
	inline void setTransporters1(int ch, double val) { transporters1[ch]=val; }
 
	inline void setTransporters2(int ch, double val) { transporters2[ch]=val; }
 
	inline void setNewTransporters1(int ch, double val) { new_transporters1[ch]=val; }
 
	inline void setNewTransporters2(int ch, double val) { new_transporters2[ch]=val; }
 
	inline double Transporters1(int ch) { return transporters1[ch]; }
 
	inline double Transporters2(int ch) { return transporters2[ch]; }
 
	
 
	//! Return true if the WallBase adheres to the SAM (shoot apical meristem)
 
	bool SAM_P(void);
 
	// NB. Not checked. If cell is not found, it returns transporters2[ch]!!
 
	//inline double getTransporter(int ch, Cell *c) { return c1 == c ? transporters1[ch] : transporters2[ch]; }
 
	
 
	//! Return true if the WallBase is a source of auxin
 
	inline bool AuxinSource(void) const { return wall_type == AuxSource; }
 
	inline bool AuxinSink(void) const { return wall_type == AuxSink; }
 
	
 
	inline void cycleWallType(void) { 
 
		
 
		if (wall_type == Normal)  
 
			wall_type = AuxSource;
 
		else
 
			if (wall_type == AuxSource) 
 
				wall_type = AuxSink;
 
			else
 
				if (wall_type == AuxSink) {
 
					wall_type = Normal;
 
				}
 
	}
 
	// checked version. Use during debugging stage.
 
	inline double getTransporter(CellBase *c, int ch) const { return c1 == c ? transporters1[ch] : ( c2 == c ? transporters2[ch] : throw "WallBase::getTransporter called with wrong cell") ; } 
 
	inline void setTransporter(CellBase *c, int ch, double val) { 
 
		if ( c1 == c ) {
 
			transporters1[ch]=val;
 
		} else 
 
			
 
			if (c2 == c ) {
 
				transporters2[ch]=val;
 
			} else {
 
				throw "WallBase::setTransporter called with wrong cell"; 
 
			}
 
	}
 
	inline double getApoplast(int ch) const { return apoplast[ch]; }
 
	inline void setApoplast(int ch, double val) { apoplast[ch] = val; }
 
	inline CellBase *getOtherCell(CellBase *c) { return c1 == c ? c2 : c1; }
 
	Vector getInfluxVector(CellBase *c);
 
	Vector getWallVector(CellBase *c);
 
	void CorrectTransporters(double orig_length);
 
	
 
	inline double Length(void) { return length; }
 
	//double Length(void);
 
	
 
	ostream &print(ostream &os) const; 
 
		
 
	void SetLength(void);
 
	void Transport(void);
 
	
 
	inline void setVizFlux( double value ) { viz_flux = value; } 
 
	
 
	/*! Return vector containing the directional flux through the wall.
 
	 as defined by the value "viz_flux" which is supplied by the end-user
 
	 in the TransportFunction.
 
	 */
 
	Vector VizFlux(void);
 
	bool IntersectsWithDivisionPlaneP(const Vector &p1, const Vector &p2);
 
	void SetTransToNewTrans( void );
 
	
 
private:
 
	
 
  }
 
  // checked version. Use during debugging stage.
 
  inline double getTransporter(CellBase *c, int ch) const
 
  { 
 
    return c1 == c ? transporters1[ch] : ( c2 == c ? transporters2[ch] : throw "WallBase::getTransporter called with wrong cell") ; } 
 

	
 
  inline void setTransporter(CellBase *c, int ch, double val) { 
 
    if ( c1 == c ) {
 
      transporters1[ch]=val;
 
    } else 
 

	
 
      if (c2 == c ) {
 
	transporters2[ch]=val;
 
      } else {
 
	throw "WallBase::setTransporter called with wrong cell"; 
 
      }
 
  }
 
  inline double getApoplast(int ch) const { return apoplast[ch]; }
 
  inline void setApoplast(int ch, double val) { apoplast[ch] = val; }
 
  inline CellBase *getOtherCell(CellBase *c) { return c1 == c ? c2 : c1; }
 
  Vector getInfluxVector(CellBase *c);
 
  Vector getWallVector(CellBase *c);
 
  void CorrectTransporters(double orig_length);
 

	
 
  inline double Length(void) { return length; }
 
  //double Length(void);
 

	
 
  ostream &print(ostream &os) const; 
 

	
 
  void SetLength(void);
 
  void Transport(void);
 

	
 
  inline void setVizFlux( double value ) { viz_flux = value; } 
 

	
 
  /*! Return vector containing the directional flux through the wall.
 
    as defined by the value "viz_flux" which is supplied by the end-user
 
    in the TransportFunction.
 
  */
 
  Vector VizFlux(void);
 
  bool IntersectsWithDivisionPlaneP(const Vector &p1, const Vector &p2);
 
  void SetTransToNewTrans( void );
 

	
 
 private:
 
};
 

	
 
ostream &operator<<(ostream &os, const WallBase &w);
 
#endif
 

	
 
/* finis */
src/wallitem.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <QDebug>
 
#include <string>
 
#include <QGraphicsScene>
 
#include <QVector>
 
#include "canvas.h"
 
#include "wallitem.h"
 
#include "parameter.h"
 
#include "node.h"
 
#include "transporterdialog.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
WallItem::WallItem( Wall *w, int wallnumber, QGraphicsScene *canvas )
 
  : QGraphicsLineItem( 0, canvas ), SimItemBase( w, canvas){
 

	
 
  wn = wallnumber;
 

	
 
  extern Parameter par;
 

	
 
	  setColor();
 
  
 
	  // line with "PIN1"is a bit inside the cell wall
 
	  Vector edgevec = (*(w->N2())) - (*(w->N1()));
 
	  Vector perp = edgevec.Normalised().Perp2D();
 
	  
 
	  Vector offs = Cell::Offset();
 
	  double factor = Cell::Factor();
 
	  
 
	  Vector from = ( offs + *(w->N1()) ) * factor + (wn==1?-1:1) * par.outlinewidth * 0.5 * factor * perp;
 
	  Vector to = ( offs + *(w->N2()) ) *factor + (wn==1?-1:1) * par.outlinewidth * 0.5 * factor * perp;
 
	  
 
	  
 
	  Vector tmp_centroid = ( *(w->N2()) + *(w->N1()) )/2.;
 
	  Vector centroid = ( offs + tmp_centroid ) * factor;
 
	  
 
	  QString text=QString("%1").arg(w->Index());
 
	  setLine(( from.x ),
 
			  ( from.y ),
 
			  ( to.x ),
 
			  ( to.y ) );
 
	  setZValue(12);
 
  }
 
  setColor();
 

	
 
  // line with "PIN1"is a bit inside the cell wall
 
  Vector edgevec = (*(w->N2())) - (*(w->N1()));
 
  Vector perp = edgevec.Normalised().Perp2D();
 

	
 
  Vector offs = Cell::Offset();
 
  double factor = Cell::Factor();
 

	
 
  Vector from = ( offs + *(w->N1()) ) * factor + (wn==1?-1:1) * par.outlinewidth * 0.5 * factor * perp;
 
  Vector to = ( offs + *(w->N2()) ) *factor + (wn==1?-1:1) * par.outlinewidth * 0.5 * factor * perp;
 

	
 

	
 
  Vector tmp_centroid = ( *(w->N2()) + *(w->N1()) )/2.;
 
  Vector centroid = ( offs + tmp_centroid ) * factor;
 

	
 
  QString text=QString("%1").arg(w->Index());
 
  setLine(( from.x ),
 
	  ( from.y ),
 
	  ( to.x ),
 
	  ( to.y ) );
 
  setZValue(12);
 
}
 

	
 

	
 
void WallItem::setColor(void) {
 

	
 
  QColor diffcolor;
 
  static const QColor purple("Purple");
 
  static const QColor blue("blue");
 
  
 

	
 
  Wall *w=&getWall();
 
  double tr = wn==1?w->Transporters1(1):w->Transporters2(1);
 
  CellBase *c = wn==1?w->C1():w->C2();
 
  diffcolor.setRgb( (int)( ( tr / (1 + tr) )*255.), 0, 0);
 
  if (w->AuxinSource() && c->BoundaryPolP()) {
 
    setPen( QPen(purple , par.outlinewidth) );
 
  } else {
 
    if (w->AuxinSink() && c->BoundaryPolP()) {
 
      setPen( QPen(blue, par.outlinewidth));
 
    } else {
 
      setPen (QPen(diffcolor, par.outlinewidth) );
 
    }
 
  }
 
}
 

	
 
void WallItem::OnClick(QMouseEvent *e) {
 
  
 

	
 

	
 
  Wall *w=&getWall();
 
#ifdef QDEBUG
 
  qDebug() << "Wall ID = " << w->Index() << ", this = " << w << endl;
 
  qDebug() << "Wall item = " << this << endl;
 
  qDebug() << "C1 = " << w->C1()->Index() << ", C2 = " << w->C2()->Index() << endl;
 
  qDebug() << "N1 = " << w->N1()->Index() << ", N2 = " << w->N2()->Index() << endl;
 
#endif
 
  CellBase *c = wn==1?w->C1():w->C2();
 

	
 
	Wall *w=&getWall();
 
	#ifdef QDEBUG
 
	qDebug() << "Wall ID = " << w->Index() << ", this = " << w << endl;
 
	qDebug() << "Wall item = " << this << endl;
 
	qDebug() << "C1 = " << w->C1()->Index() << ", C2 = " << w->C2()->Index() << endl;
 
	qDebug() << "N1 = " << w->N1()->Index() << ", N2 = " << w->N2()->Index() << endl;
 
	#endif
 
	CellBase *c = wn==1?w->C1():w->C2();
 
  TransporterDialog dialog(w, c, wn);
 
  dialog.exec();
 

	
 
	TransporterDialog dialog(w, c, wn);
 
	dialog.exec();
 
  if (e->button() == Qt::RightButton) {
 
    QString message;
 
    if (wn==1) {
 
      message=QString("Transporter 1 = %1, color = %2, length = %3\n").arg(w->Transporters1(1)).arg(pen().color().red()).arg(getWall().Length());
 
    } else {
 
      message=QString("Transporter 2 = %1, color = %2, length = %3\n").arg(w->Transporters2(1)).arg(pen().color().red()).arg(getWall().Length());
 
    }
 

	
 
	if (e->button() == Qt::RightButton) {
 
		QString message;
 
		if (wn==1) {
 
			message=QString("Transporter 1 = %1, color = %2, length = %3\n").arg(w->Transporters1(1)).arg(pen().color().red()).arg(getWall().Length());
 
		} else {
 
			message=QString("Transporter 2 = %1, color = %2, length = %3\n").arg(w->Transporters2(1)).arg(pen().color().red()).arg(getWall().Length());
 
		}
 
		
 
		//extern MainBase *main_window;
 
		
 
    //extern MainBase *main_window;
 

	
 
  } else {
 
    if (e->button() == Qt::LeftButton) {
 
      if (c->BoundaryPolP()) {
 
	w->cycleWallType();
 
      } else {
 
	if (e->modifiers() == Qt::ShiftModifier) {
 
	  wn==1?w->setTransporters1(1,0):w->setTransporters2(1,0);					
 

	
 
	} else {
 
		if (e->button() == Qt::LeftButton) {
 
			if (c->BoundaryPolP()) {
 
				w->cycleWallType();
 
			} else {
 
				if (e->modifiers() == Qt::ShiftModifier) {
 
					wn==1?w->setTransporters1(1,0):w->setTransporters2(1,0);					
 
					
 
				} else {
 
					// set high amount of PIN1
 
					//cerr << "Setting PIN1\n";
 
					wn==1?w->setTransporters1(1,10):w->setTransporters2(1,10);
 
				}
 
			}
 
			setColor();
 
			update(boundingRect());
 
		} 
 
	  // set high amount of PIN1
 
	  //cerr << "Setting PIN1\n";
 
	  wn==1?w->setTransporters1(1,10):w->setTransporters2(1,10);
 
	}
 
      }
 
      setColor();
 
      update(boundingRect());
 
    } 
 
  }
 
}
 

	
 
/* finis */
src/wallitem.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _WALLITEM_H_
 
#define _WALLITEM_H_
 

	
 
#include <QGraphicsScene>
 
#include <QGraphicsLineItem>
 
#include <QPainter>
 
#include <qpainter.h>
 
#include <QMouseEvent>
 
#include "simitembase.h"
 
#include "wall.h"
 

	
 
//! Shows transporter concentrations at one side of the wall
 

	
 
class WallItem : public QGraphicsLineItem, public SimItemBase
 
{
 
public:
 
 public:
 
  WallItem( Wall *n, int wallnumber, QGraphicsScene *canvas );
 
  virtual ~WallItem() {}
 
  Wall &getWall(void) const { return *class_cast<Wall*>(obj); }
 
  void OnClick(QMouseEvent *e);  
 
  void setColor(void);
 
 private:
 
  int wn;
 
};
 

	
 
#endif
 

	
 
/* finis */
src/warning.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include <stdarg.h>
 
#include <stdio.h>
 
#include <stdlib.h>
 
#include <iostream>
 
#include "warning.h"
 
#ifdef QTGRAPHICS
 
#include <qapplication.h>
 
#include "canvas.h"
 
#endif
 
#include <QMessageBox>
 

	
 
static const std::string _module_id("$Id$");
 

	
 
int Quiet=0;
 

	
 
/*
 
 * ERROR: scream and die quickly.
 
 */
 

	
 
#ifndef QTGRAPHICS
 
void MyWarning::error(char * fmt, ...)
 
{
 
    va_list ap;
 
  va_list ap;
 

	
 
    va_start(ap, fmt);
 
    vfprintf(stderr, fmt, ap);		/* invoke interface to printf       */
 
    fprintf(stderr,"\n");     /* automatic \n by Roeland */
 
    fflush(stderr);			/* drain std error buffer 	    */
 
    va_end(ap);
 
    exit(1);				/* quit with error status	    */
 
  va_start(ap, fmt);
 
  vfprintf(stderr, fmt, ap);		/* invoke interface to printf       */
 
  fprintf(stderr,"\n");     /* automatic \n by Roeland */
 
  fflush(stderr);			/* drain std error buffer 	    */
 
  va_end(ap);
 
  exit(1);				/* quit with error status	    */
 
}
 
#else
 
//#include <qmessagebox.h>
 
#include "UniqueMessage.h"
 
void MyWarning::error(const char *fmt, ...)
 
{
 
  va_list ap;
 
  if (Quiet) return;
 
  char *message = new char[1000];
 
 
 

	
 
  va_start(ap, fmt);
 
  vsnprintf(message, 999, fmt, ap);		/* invoke interface to printf       */
 
  va_end(ap);
 
  
 

	
 
  QString qmess(message);
 
  
 

	
 
  if (qApp->type()==QApplication::Tty) {
 
    // batch mode: print the message to stderr
 
    fprintf(stderr, "Fatal error: %s\n",qmess.toStdString().c_str());
 
    exit(1);
 
  } else { // issue a dialog box
 
    /* Solve this with signal and slot...! */
 
	  //extern MainBase *main_window;
 
    //extern MainBase *main_window;
 
    //((Main *)main_window)->stopSimulation();
 
    
 
	QMessageBox::critical( 0 , "Fatal error", qmess, QMessageBox::Abort, QMessageBox::NoButton, QMessageBox::NoButton );
 

	
 
    QMessageBox::critical( 0 , "Fatal error", qmess, QMessageBox::Abort, QMessageBox::NoButton, QMessageBox::NoButton );
 
    fprintf(stderr, "Error: %s\n",qmess.toStdString().c_str());
 
    QCoreApplication::exit(1);
 
    std::exit(1);
 
  }
 
  delete[] message;
 
  
 
}
 
#endif
 

	
 

	
 
/*
 
 * EPRINTF: scream, but don't die yet.
 
 * Roeland changed this to "warning" (21/10/1998)
 
 * and added an automatic "\n"
 
 */
 

	
 
#ifndef QTGRAPHICS
 
void MyWarning::warning(const char * fmt, ...)
 
{
 
  va_list ap;
 
  if (Quiet) return;
 
  
 

	
 
  va_start(ap, fmt);
 
  vfprintf(stderr, fmt, ap);		/* invoke interface to printf       */
 
  fprintf(stderr,"\n");     /* automatic \n by Roeland */
 
  fflush(stderr);			/* drain std error buffer 	    */
 
  va_end(ap);
 
}
 
#else 
 

	
 
#include <qmessagebox.h>
 

	
 

	
 
void MyWarning::warning(const char *fmt, ...)
 
{
 
  va_list ap;
 
  if (Quiet) return;
 
  char *message = new char[1000];
 
 
 

	
 
  va_start(ap, fmt);
 
  vsnprintf(message, 999, fmt, ap);		/* invoke interface to printf       */
 
  va_end(ap);
 
  
 

	
 
  QString qmess(message);
 
  
 

	
 
  //  bool batch = false;
 
  
 

	
 
  if (qApp->type()==QApplication::Tty) {
 
    // batch mode: print the message to stderr
 
    fprintf(stderr, "Warning: %s\n",qmess.toStdString().c_str());
 
  } else { // issue a dialog box
 
	  UniqueMessageBox msgBox( QString("Warning"), qmess );
 
	  msgBox.exec();
 
    UniqueMessageBox msgBox( QString("Warning"), qmess );
 
    msgBox.exec();
 
  }
 
  delete[] message;
 

	
 
}
 
#endif
 

	
 
/*! Issues a warning only once,
 
  by comparing it to a list of warnings issued previously. */
 
void MyWarning::unique_warning(const char *fmt, ...) {
 
  
 

	
 
  va_list ap;
 
  if (Quiet) return;
 
  char *message = new char[1000];
 
 
 

	
 
  va_start(ap, fmt);
 
  vsnprintf(message, 999, fmt, ap);		/* invoke interface to printf       */
 
  va_end(ap);
 

	
 
  static vector<string> previous_warnings;
 
  
 

	
 
  // search warning in list
 
  if (find(
 
	   previous_warnings.begin(),previous_warnings.end(), 
 
	   string(message)) 
 
      ==previous_warnings.end()) {
 
    
 

	
 
    // new warning, store in list
 
    previous_warnings.push_back(string(message));
 
    
 

	
 
    // issue warning
 
    warning("%s", message);
 
   
 

	
 
  } else {
 
    // don't issue warning
 
    return;
 
  }
 
}
 

	
 

	
 
#ifdef TESTBED
 

	
 
main(int argc, char * argv[])
 
{
 
    eprintf("warning: foo=%f\tbar=%d\tfum=\"%s\"\n", 3.1415, 32768, "waldo");
 
    error("error: foo=%f\tbar=%d\tfum=\"%s\"\n", 3.1415, 32768, "waldo");
 
  eprintf("warning: foo=%f\tbar=%d\tfum=\"%s\"\n", 3.1415, 32768, "waldo");
 
  error("error: foo=%f\tbar=%d\tfum=\"%s\"\n", 3.1415, 32768, "waldo");
 
}
 

	
 
#endif
 

	
 
/* finis */
src/warning.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _WARNING_H_
 
#define _WARNING_H_
 

	
 
#define MEMORYCHECK(x) if ((x)==NULL) {   fprintf(stderr, "Out of Memory error in "#x" \n");  exit(0); }
 

	
 
#define UNIDENTIFIED 2353996
 

	
 
#ifdef __cplusplus 
 
extern "C" { 
 
#endif
 
  // namespace MyWarning needed because libxml2 also defines a warning token.
 
    
 

	
 
  namespace MyWarning {
 
    void error(const char *, ...);
 
    void warning(const char *, ...);
 
    void unique_warning(const char *, ...);
 
  }
 
  
 

	
 
#ifdef __cplusplus
 
}
 
#endif
 

	
 
#endif
 

	
 
/* finis */
src/xmlwrite.cpp
Show inline comments
 
/*
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include "mesh.h"
 
#include "parameter.h"
 

	
 
#include <ctime>
 
#include <cstring>
 
#include <string>
 
#include <sstream>
 
#include <QString>
 
#include <libxml/parser.h>
 
#include <libxml/tree.h>
 
#include <libxml/xpath.h>
 
#include <libxml/xmlreader.h>
 
#include <QLocale>
 
#include "xmlwrite.h"
 
#include "nodeset.h"
 
#include "warning.h"
 
#include "output.h" 
 

	
 
static const std::string _module_id("$Id$");
 

	
 
using namespace MyWarning;
 

	
 
void ThrowStringStream(stringstream &s) {
 
	
 
	static char *msg = 0;
 
	msg = (char *)malloc((1+s.str().length())*sizeof(char));
 
	strcpy(msg,s.str().c_str());
 
	throw(msg);
 

	
 
  static char *msg = 0;
 
  msg = (char *)malloc((1+s.str().length())*sizeof(char));
 
  strcpy(msg,s.str().c_str());
 
  throw(msg);
 
}
 

	
 

	
 
// Add this cell to the XML tree
 
void Cell::XMLAdd(xmlNodePtr cells_node) const {
 

	
 
  // Save the cell to a stream so we can reconstruct its state later
 
  xmlNodePtr xmlcell = xmlNewChild(cells_node, NULL, BAD_CAST "cell",NULL);
 
  XMLAddCore(xmlcell);
 

	
 
}
 

	
 
void BoundaryPolygon::XMLAdd(xmlNodePtr parent_node) const {
 
  
 

	
 
  xmlNodePtr xmlcell = xmlNewChild(parent_node, NULL, BAD_CAST "boundary_polygon",NULL);
 
  XMLAddCore(xmlcell);
 

	
 
}
 

	
 
void NodeSet::XMLAdd(xmlNode *root) const {
 
  
 

	
 
  xmlNode *xmlnodeset = xmlNewChild(root, NULL, BAD_CAST "nodeset", NULL);
 
  
 

	
 
  for (list<Node *>::const_iterator i=begin();i!=end();i++) {
 
    {
 
      ostringstream text;
 
      xmlNodePtr node_xml = xmlNewChild(xmlnodeset, NULL, BAD_CAST "node", NULL);
 
      text << (*i)->Index();
 
      xmlNewProp(node_xml, BAD_CAST "n", BAD_CAST text.str().c_str());
 
    }
 
  }
 
  
 
}
 

	
 

	
 

	
 

	
 
void Cell::XMLAddCore(xmlNodePtr xmlcell) const {
 
  
 

	
 
  // properties
 

	
 
  {
 
    ostringstream text;
 
    text << index;
 
    xmlNewProp(xmlcell, BAD_CAST "index" , BAD_CAST text.str().c_str() );
 
  }
 
  {
 
    ostringstream text;
 
    text << area;
 
    xmlNewProp(xmlcell, BAD_CAST "area", BAD_CAST text.str().c_str());
 
  }
 
  
 

	
 
  {
 
    ostringstream text;
 
    text << target_area;
 
    xmlNewProp(xmlcell, BAD_CAST "target_area", BAD_CAST text.str().c_str());
 
  }
 
 
 
  
 

	
 

	
 
  {
 
    ostringstream text;
 
    text << target_length;
 
    xmlNewProp(xmlcell, BAD_CAST "target_length", BAD_CAST text.str().c_str());
 
  }
 
 
 

	
 
  {
 
    ostringstream text;
 
    text << lambda_celllength;
 
    xmlNewProp(xmlcell, BAD_CAST "lambda_celllength", BAD_CAST text.str().c_str());
 
  }
 
 
 

	
 
  {
 
    ostringstream text;
 
    text << stiffness;
 
    xmlNewProp(xmlcell, BAD_CAST "stiffness", BAD_CAST text.str().c_str());
 
  }
 
 
 

	
 
  {
 
    ostringstream text;
 
    text << bool_name(fixed);
 
    xmlNewProp(xmlcell, BAD_CAST "fixed", BAD_CAST text.str().c_str());
 
  }
 
  
 

	
 
  {
 
    ostringstream text;
 
    text << bool_name(pin_fixed);
 
    xmlNewProp(xmlcell, BAD_CAST "pin_fixed", BAD_CAST text.str().c_str());
 
  }
 

	
 
  {
 
    ostringstream text;
 
    text << bool_name(at_boundary);
 
    xmlNewProp(xmlcell, BAD_CAST "at_boundary", BAD_CAST text.str().c_str());
 
  }
 
  
 
   
 

	
 

	
 
  {
 
    ostringstream text;
 
    text << bool_name(dead);
 
    xmlNewProp(xmlcell, BAD_CAST "dead", BAD_CAST text.str().c_str());
 
  }
 

	
 
  {
 
    ostringstream text;
 
    text << bool_name(source);
 
    xmlNewProp(xmlcell, BAD_CAST "source", BAD_CAST text.str().c_str());
 
  }
 

	
 
  
 

	
 
  {
 
    ostringstream text;
 
    text << boundary_type_names[boundary];
 
    xmlNewProp(xmlcell, BAD_CAST "boundary", BAD_CAST text.str().c_str());
 
  }
 
  
 

	
 
  {
 
    ostringstream text;
 
    text << div_counter;
 
    xmlNewProp(xmlcell, BAD_CAST "div_counter", BAD_CAST text.str().c_str());
 
  }
 
  
 
	{ 
 
		ostringstream text;
 
		text << cell_type;
 
		xmlNewProp(xmlcell, BAD_CAST "cell_type", BAD_CAST text.str().c_str());
 
	}
 
    
 

	
 
  { 
 
    ostringstream text;
 
    text << cell_type;
 
    xmlNewProp(xmlcell, BAD_CAST "cell_type", BAD_CAST text.str().c_str());
 
  }
 

	
 
  for (list<Node *>::const_iterator i=nodes.begin();i!=nodes.end();i++) {
 
    {
 
      ostringstream text;
 
      xmlNodePtr node_xml = xmlNewChild(xmlcell, NULL, BAD_CAST "node", NULL);
 
      text << (*i)->Index();
 
      xmlNewProp(node_xml, BAD_CAST "n", BAD_CAST text.str().c_str());
 
    }
 
  }
 

	
 
  for (list<Wall *>::const_iterator i=walls.begin();i!=walls.end();i++) {
 
    {
 
      ostringstream text;
 
      xmlNodePtr wall_xml = xmlNewChild(xmlcell, NULL, BAD_CAST "wall", NULL);
 
      text << XMLIO::list_index( m->walls.begin(), m->walls.end(), *i );
 
      xmlNewProp(wall_xml, BAD_CAST "w", BAD_CAST text.str().c_str());
 
    }
 
  }
 

	
 
  
 
  
 
  
 

	
 

	
 

	
 
  xmlNodePtr chem_xml = xmlNewChild(xmlcell, NULL, BAD_CAST "chem", NULL); 
 
  {
 
    ostringstream text;
 
    text << NChem();
 
    xmlNewProp(chem_xml, BAD_CAST "n", BAD_CAST text.str().c_str());
 
  }
 
  
 

	
 
  for (int i=0;i<NChem();i++) {
 
    xmlNodePtr chem_val_xml = xmlNewChild(chem_xml, NULL, BAD_CAST "val", NULL);
 
    { 
 
      ostringstream text;
 
      text << chem[i];
 
      xmlNewProp(chem_val_xml, BAD_CAST "v", BAD_CAST text.str().c_str());
 

	
 
    }
 
  }
 
  
 
  
 

	
 
}
 

	
 

	
 

	
 
void Node::XMLAdd(xmlNodePtr nodes_node) const { 
 
  
 

	
 
  // Save the node to a stream so we can reconstruct its state later
 
  xmlNodePtr xmlnode = xmlNewChild(nodes_node, NULL, BAD_CAST "node",NULL);
 

	
 
  
 
  
 
  {
 
    ostringstream text;
 
    text << x;
 
    xmlNewProp(xmlnode, BAD_CAST "x", BAD_CAST text.str().c_str());
 
  }
 
  
 

	
 
  {
 
    ostringstream text;
 
    text << y;
 
    xmlNewProp(xmlnode, BAD_CAST "y", BAD_CAST text.str().c_str());
 
  }
 

	
 
  {
 
    ostringstream text;
 
    text << bool_name(fixed);
 
    xmlNewProp(xmlnode, BAD_CAST "fixed", BAD_CAST text.str().c_str());
 
  }
 
  
 

	
 
  {
 
    ostringstream text;
 
    text << bool_name(boundary);
 
    xmlNewProp(xmlnode, BAD_CAST "boundary", BAD_CAST text.str().c_str());
 
  }
 

	
 
  {
 
    ostringstream text;
 
    text << bool_name(sam);
 
    xmlNewProp(xmlnode, BAD_CAST "sam", BAD_CAST text.str().c_str());
 
  }
 

	
 
  if (node_set) {
 
    ostringstream text;
 
    text << XMLIO::list_index(m->node_sets.begin(),m->node_sets.end(),node_set);
 
    xmlNewProp(xmlnode, BAD_CAST "nodeset", BAD_CAST text.str().c_str());    
 
  }
 
  
 

	
 
}
 

	
 
void Neighbor::XMLAdd(xmlNodePtr neighbors_node) const {
 
  
 

	
 
  xmlNodePtr xmlnode = xmlNewChild(neighbors_node, NULL, BAD_CAST "neighbor",NULL);
 
  {
 
    ostringstream text;
 
    text << cell->Index();
 
    xmlNewProp(xmlnode, BAD_CAST "cell", BAD_CAST text.str().c_str());
 
  }
 

	
 
  {
 
    ostringstream text;
 
    text << nb1->Index();
 
    xmlNewProp(xmlnode, BAD_CAST "nb1", BAD_CAST text.str().c_str());
 
  }
 

	
 
  {
 
    ostringstream text;
 
    text << nb2->Index();
 
    xmlNewProp(xmlnode, BAD_CAST "nb2", BAD_CAST text.str().c_str());
 
  }
 

	
 
}
 

	
 

	
 
// from example code on www.libxml.org:
 
xmlXPathObjectPtr
 
getnodeset (xmlDocPtr doc, xmlChar *xpath){
 
	
 

	
 
  xmlXPathContextPtr context;
 
  xmlXPathObjectPtr result;
 

	
 
  context = xmlXPathNewContext(doc);
 
  if (context == NULL) {
 
    //printf("Error in xmlXPathNewContext\n");
 
    return NULL;
 
  }
 
  result = xmlXPathEvalExpression(xpath, context);
 
  xmlXPathFreeContext(context);
 
  if (result == NULL) {
 
    //printf("Error in xmlXPathEvalExpression\n");
 
    return NULL;
 
  }
 
  if(xmlXPathNodeSetIsEmpty(result->nodesetval)){
 
    xmlXPathFreeObject(result);
 
    // printf("No result\n");
 
    return NULL;
 
  }
 
  return result;
 
}
 

	
 

	
 

	
 
int Cell::XMLRead(xmlNode *cur)  {
 
  
 
int Cell::XMLRead(xmlNode *cur)
 
{
 

	
 
  xmlNode *n = cur->xmlChildrenNode;
 
  QLocale standardlocale(QLocale::C);
 
  bool ok;
 

	
 
  vector<int> tmp_nodes;
 

	
 
	while(n!=NULL) {
 
  while(n!=NULL) {
 
    if ((!xmlStrcmp(n->name, (const xmlChar *)"node"))) {
 
      xmlChar *nc = xmlGetProp(n, BAD_CAST "n");
 

	
 
      if (nc==0) {
 
	unique_warning("Token \"n\" not found in xmlwrite.cpp at or around line no. 966");
 
      }
 
      tmp_nodes.push_back(atoi( (char *)nc));
 
      xmlFree(nc);
 

	
 
    }
 
    n = n->next;
 
  }
 
      
 

	
 
  int nnodes = tmp_nodes.size();
 
  for (int i=0;i<nnodes;i++) {
 
    m->AddNodeToCell( this, 
 
		      m->nodes[tmp_nodes[i]], 
 
		      m->nodes[tmp_nodes[(nnodes+i-1)%nnodes]],
 
		      m->nodes[tmp_nodes[(i+1)%nnodes]] );
 
	
 

	
 
  }
 

	
 
  n = cur->xmlChildrenNode;
 
  while(n!=NULL) {
 
	  if ((!xmlStrcmp(n->name, (const xmlChar *)"chem"))) {
 
    if ((!xmlStrcmp(n->name, (const xmlChar *)"chem"))) {
 

	
 
      xmlNode *v_node = n->xmlChildrenNode;
 
      int nv=0;
 
      while (v_node!=NULL) {
 
	if ((!xmlStrcmp(v_node->name, (const xmlChar *)"val"))) {
 

	
 
	    xmlNode *v_node = n->xmlChildrenNode;
 
	    int nv=0;
 
	    while (v_node!=NULL) {
 
	      if ((!xmlStrcmp(v_node->name, (const xmlChar *)"val"))) {
 
		
 
		
 
		if (nv>=Cell::NChem()) {
 
		  {
 
		    stringstream text;
 
		    text << "Exception in Mesh::XMLRead: Too many chemical values given for cell(s). Ignoring remaining values.";
 
		    unique_warning(text.str().c_str());
 
		    break;
 
		  }
 
		}
 
		
 
		xmlChar *nc = xmlGetProp(v_node, (const xmlChar *) "v");
 
		
 
		if (nc==0) {
 
		  unique_warning("Token \"v\" not found in xmlwrite.cpp at or around line no. 1002");
 
		}
 
		double v=standardlocale.toDouble((char *)nc, &ok);
 
		if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(char *)nc);
 
		chem[nv++]=v;
 
		xmlFree(nc);
 
	      }
 
	      v_node = v_node->next; 
 

	
 
	  if (nv>=Cell::NChem()) {
 
	    {
 
	      stringstream text;
 
	      text << "Exception in Mesh::XMLRead: Too many chemical values given for cell(s). Ignoring remaining values.";
 
	      unique_warning(text.str().c_str());
 
	      break;
 
	    }
 
	  }
 
	  n = n->next;
 

	
 
	  xmlChar *nc = xmlGetProp(v_node, (const xmlChar *) "v");
 

	
 
	  if (nc==0) {
 
	    unique_warning("Token \"v\" not found in xmlwrite.cpp at or around line no. 1002");
 
	  }
 
	  double v=standardlocale.toDouble((char *)nc, &ok);
 
	  if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(char *)nc);
 
	  chem[nv++]=v;
 
	  xmlFree(nc);
 
	}
 
	v_node = v_node->next; 
 
      }
 
    }
 
    n = n->next;
 
  }
 
	
 
	// read cell properties
 
	{
 
		xmlChar *v_str = xmlGetProp(cur, BAD_CAST "area");
 
		
 
		if (v_str==0) {
 
			unique_warning("Token \"area\" not found in xmlwrite.cpp at or around line no. 1018");
 
		}
 
		if (v_str != NULL) {
 
			area=standardlocale.toDouble((char *)v_str, &ok);
 
			if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(char *)v_str);
 
			xmlFree(v_str);
 
		}
 
	}
 
	
 
	{
 
		xmlChar *v_str = xmlGetProp(cur, BAD_CAST "target_area");
 
		
 
		if (v_str==0) {
 
			unique_warning("Token \"target_area\" not found in xmlwrite.cpp at or around line no. 1029");
 
		}
 

	
 
  // read cell properties
 
  {
 
    xmlChar *v_str = xmlGetProp(cur, BAD_CAST "area");
 

	
 
    if (v_str==0) {
 
      unique_warning("Token \"area\" not found in xmlwrite.cpp at or around line no. 1018");
 
    }
 
    if (v_str != NULL) {
 
      	target_area=standardlocale.toDouble((char *)v_str, &ok);
 
	if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(char *)v_str);
 
      area=standardlocale.toDouble((char *)v_str, &ok);
 
      if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(char *)v_str);
 
      xmlFree(v_str);
 
    }
 
  }
 
      
 
      
 

	
 
  {
 
    xmlChar *v_str = xmlGetProp(cur, BAD_CAST "target_area");
 

	
 
    if (v_str==0) {
 
      unique_warning("Token \"target_area\" not found in xmlwrite.cpp at or around line no. 1029");
 
    }
 
    if (v_str != NULL) {
 
      target_area=standardlocale.toDouble((char *)v_str, &ok);
 
      if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(char *)v_str);
 
      xmlFree(v_str);
 
    }
 
  }
 

	
 

	
 
  {
 
    xmlChar *v_str = xmlGetProp(cur, BAD_CAST "target_length");
 

	
 
    if (v_str==0) {
 
      unique_warning("Token \"target_length\" not found in xmlwrite.cpp at or around line no. 1041");
 
    }
 
    if (v_str != NULL) {
 
      target_length=standardlocale.toDouble((char *)v_str, &ok);
 
      if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(char *)v_str);
 
      xmlFree(v_str);
 
    }
 
  }
 

	
 
  {
 
    xmlChar *v_str = xmlGetProp(cur, BAD_CAST "lambda_celllength");
 

	
 
    if (v_str==0) {
 
      unique_warning("Token \"lambda_celllength\" not found in xmlwrite.cpp at or around line no. 1052");
 
    }
 
    if (v_str != NULL) {
 
      lambda_celllength=standardlocale.toDouble((char *)v_str, &ok);
 
      if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(char *)v_str);
 
      xmlFree(v_str);
 
    }
 
  }
 

	
 
  {
 
    xmlChar *v_str = xmlGetProp(cur, BAD_CAST "stiffness");
 

	
 
    if (v_str==0) {
 
      unique_warning("Token \"stiffness\" not found in xmlwrite.cpp at or around line no. 1063");
 
    }
 
    if (v_str != NULL) {
 
      stiffness=standardlocale.toDouble((char *)v_str, &ok);
 
      if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(char *)v_str);
 
      xmlFree(v_str);
 
    }
 
  }
 

	
 
      
 

	
 
  {
 
    xmlChar *v_str = xmlGetProp(cur, BAD_CAST "fixed");
 

	
 
    if (v_str==0) {
 
      unique_warning("Token \"fixed\" not found in xmlwrite.cpp at or around line no. 1075");
 
    }
 
    if (v_str != NULL) {
 
      fixed = strtobool( (char *)v_str);
 
      xmlFree(v_str);
 
    }
 
  }
 

	
 
  {
 
    xmlChar *v_str = xmlGetProp(cur, BAD_CAST "pin_fixed");
 

	
 
    if (v_str==0) {
 
      unique_warning("Token \"pin_fixed\" not found in xmlwrite.cpp at or around line no. 1086");
 
    }
 
    if (v_str != NULL) {
 
      pin_fixed = strtobool( (char *)v_str);
 
      xmlFree(v_str);
 
    }
 
  }
 
      
 

	
 
  {
 
    xmlChar *v_str = xmlGetProp(cur, BAD_CAST "at_boundary");
 

	
 
    if (v_str==0) {
 
      unique_warning("Token \"at_boundary\" not found in xmlwrite.cpp at or around line no. 1097");
 
    }
 
    if (v_str != NULL) {
 
      at_boundary = strtobool( (char *)v_str);
 
      xmlFree(v_str);
 
    }
 
  }
 
      
 

	
 
  {
 
    xmlChar *v_str = xmlGetProp(cur, BAD_CAST "dead");
 

	
 
    if (v_str==0) {
 
      unique_warning("Token \"dead\" not found in xmlwrite.cpp at or around line no. 1108");
 
    }
 
    if (v_str != NULL) {
 
      dead = strtobool( (char *)v_str);
 
      xmlFree(v_str);
 
    }
 
  }
 

	
 
  {
 
    xmlChar *v_str = xmlGetProp(cur, BAD_CAST "source");
 

	
 
    if (v_str==0) {
 
      unique_warning("Token \"source\" not found in xmlwrite.cpp at or around line no. 1119");
 
    }
 
    if (v_str != NULL) {
 
      source = strtobool( (char *)v_str);
 
      xmlFree(v_str);
 
    }
 
  }
 
      
 

	
 
  {
 
    xmlChar *v_str = xmlGetProp(cur, BAD_CAST "boundary");
 

	
 
    if (v_str==0) {
 
      unique_warning("Token \"boundary\" not found in xmlwrite.cpp at or around line no. 1130");
 
    }
 
    if (v_str != NULL) {
 
      for (int i=0;i<4;i++) {
 
	if (!xmlStrcmp( v_str, (const xmlChar *)Cell::boundary_type_names[i])) {
 
	  boundary=(Cell::boundary_type)i;
 
	  break;
 
	}
 
      }
 
      xmlFree(v_str);
 
    }
 
  }
 
  
 

	
 
  {
 
    xmlChar *v_str = xmlGetProp(cur, BAD_CAST "div_counter");
 

	
 
    if (v_str==0) {
 
      unique_warning("Token \"div_counter\" not found in xmlwrite.cpp at or around line no. 1119");
 
    }
 
    if (v_str != NULL) {
 
      div_counter = atoi( (char *)v_str);
 
      xmlFree(v_str);
 
    }
 
  }
 
	
 
	{
 
		xmlChar *v_str = xmlGetProp(cur, BAD_CAST "cell_type");
 
		
 
		if (v_str==0) {
 
			unique_warning("Token \"cell_type\" not found in xmlwrite.cpp at or around line no. 1237");
 
		}
 
		if (v_str != NULL) {
 
			cell_type = atoi( (char *)v_str);
 
			xmlFree(v_str);
 
		}
 
	}
 
  
 

	
 
  {
 
    xmlChar *v_str = xmlGetProp(cur, BAD_CAST "cell_type");
 

	
 
    if (v_str==0) {
 
      unique_warning("Token \"cell_type\" not found in xmlwrite.cpp at or around line no. 1237");
 
    }
 
    if (v_str != NULL) {
 
      cell_type = atoi( (char *)v_str);
 
      xmlFree(v_str);
 
    }
 
  }
 

	
 
  // Recalculate moments and area
 
  SetIntegrals();
 
  return 0;
 
}
 

	
 
}
 
  
 
void NodeSet::XMLRead(xmlNode *root, Mesh *m) {
 
  
 
void NodeSet::XMLRead(xmlNode *root, Mesh *m)
 
{
 

	
 
  xmlNode *n = root->xmlChildrenNode;
 
  
 

	
 
  vector<int> tmp_nodes;
 
  while(n!=NULL) {
 
    if ((!xmlStrcmp(n->name, (const xmlChar *)"node"))) {
 
      xmlChar *nc = xmlGetProp(n, BAD_CAST "n");
 

	
 
      if (nc==0) {
 
	unique_warning("Token \"n\" not found in xmlwrite.cpp at or around line no. 966");
 
      }
 
      tmp_nodes.push_back(atoi( (char *)nc));
 
      xmlFree(nc);
 
    }
 
    n = n->next;
 
  }
 
  
 

	
 
  int nnodes = tmp_nodes.size();
 
  for (int i=0;i<nnodes;i++) {
 
    AddNode( &(m->getNode(tmp_nodes[i])) );
 
  }
 
  
 
}
 

	
 

	
 

	
 

	
 
void Wall::XMLAdd(xmlNode *parent) const { 
 
  
 

	
 
  // Save the node to a stream so we can reconstruct its state later
 
  xmlNodePtr xmlwall = xmlNewChild(parent, NULL, BAD_CAST "wall",NULL);
 
  
 

	
 
  {
 
    ostringstream text;
 
    text << Index();
 
    xmlNewProp(xmlwall, BAD_CAST "index" , BAD_CAST text.str().c_str() );
 
  }
 

	
 
  {
 
    ostringstream text;
 
    text << c1->Index();
 
    xmlNewProp(xmlwall, BAD_CAST "c1", BAD_CAST text.str().c_str());
 
  }
 
  
 
  
 

	
 

	
 
  {
 
    ostringstream text;
 
    text << c2->Index();
 
    xmlNewProp(xmlwall, BAD_CAST "c2", BAD_CAST text.str().c_str());
 
  }
 
  
 

	
 

	
 
  {
 
    ostringstream text;
 
    text << n1->Index();
 
    xmlNewProp(xmlwall, BAD_CAST "n1", BAD_CAST text.str().c_str());
 
  }
 
  
 

	
 
  {
 
    ostringstream text;
 
    text << n2->Index();
 
    xmlNewProp(xmlwall, BAD_CAST "n2", BAD_CAST text.str().c_str());
 
  }
 

	
 
  {
 
    ostringstream text;
 
    text << length;
 
    xmlNewProp(xmlwall, BAD_CAST "length", BAD_CAST text.str().c_str());
 
  }
 
    
 

	
 

	
 
  {
 
    ostringstream text;
 
    text << viz_flux;
 
    xmlNewProp(xmlwall, BAD_CAST "viz_flux", BAD_CAST text.str().c_str());
 
  }
 

	
 
  {
 
    ostringstream text;
 
    text << WallTypetoStr(wall_type);
 
    xmlNewProp(xmlwall, BAD_CAST "wall_type", BAD_CAST text.str().c_str());
 
  }
 
      
 
    
 

	
 

	
 
  xmlNodePtr tr1_xml = xmlNewChild(xmlwall, NULL, BAD_CAST "transporters1", NULL); 
 
  if (transporters1) {
 
    for (int i=0;i<Cell::NChem();i++) {
 
      xmlNodePtr tr1_val_xml = xmlNewChild(tr1_xml, NULL, BAD_CAST "val", NULL);
 
      { 
 
	ostringstream text;
 
	text << transporters1[i];
 
	xmlNewProp(tr1_val_xml, BAD_CAST "v", BAD_CAST text.str().c_str());
 
      
 

	
 
      }
 
    }
 
  }
 
  if (transporters2) {
 
    xmlNodePtr tr2_xml = xmlNewChild(xmlwall, NULL, BAD_CAST "transporters2", NULL); 
 
  
 

	
 
    for (int i=0;i<Cell::NChem();i++) {
 
      xmlNodePtr tr2_val_xml = xmlNewChild(tr2_xml, NULL, BAD_CAST "val", NULL);
 
      { 
 
	ostringstream text;
 
	text << transporters2[i];
 
	xmlNewProp(tr2_val_xml, BAD_CAST "v", BAD_CAST text.str().c_str());
 
      
 
      }
 
    }
 
  }
 
   
 

	
 
  if (apoplast) {
 
    xmlNodePtr apo_xml = xmlNewChild(xmlwall, NULL, BAD_CAST "apoplast", NULL); 
 
  
 

	
 
    for (int i=0;i<Cell::NChem();i++) {
 
      xmlNodePtr apo_val_xml = xmlNewChild(apo_xml, NULL, BAD_CAST "val", NULL);
 
      { 
 
	ostringstream text;
 
	text << transporters2[i];
 
	xmlNewProp(apo_val_xml, BAD_CAST "v", BAD_CAST text.str().c_str());
 
	
 
      }
 
    }
 
  } 
 
}
 

	
 

	
 
vector<double> XMLIO::XMLReadValArray(xmlNode *cur) {
 
  
 
vector<double> XMLIO::XMLReadValArray(xmlNode *cur)
 
{
 

	
 
  vector<double> result;
 
  QLocale standardlocale(QLocale::C);
 
  bool ok;
 

	
 
  xmlNode *valarray_node = cur->xmlChildrenNode;
 
  while (valarray_node!=NULL) {
 
    if (!xmlStrcmp(valarray_node->name, (const xmlChar *)"val")) {
 
      xmlChar *vc = xmlGetProp(valarray_node, BAD_CAST "v");
 
      if (vc) {
 
	//result.push_back(strtod( (const char *)vc, 0));
 
	result.push_back(standardlocale.toDouble((char *)vc, &ok));
 
	if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(char *)vc);
 
	xmlFree(vc);
 
      }
 
      
 

	
 
    }
 
    valarray_node = valarray_node->next;
 
  }
 
  return result;
 
}
 

	
 
void Mesh::XMLSave(const char *docname, xmlNode *options) const
 
{
 
	
 
	// based on libxml2 example code "tree2.c"
 
	
 
	xmlDocPtr doc = NULL;       /* document pointer */
 
	xmlNodePtr root_node = NULL;/* node pointers */
 
	//xmlDtdPtr dtd = NULL;       /* DTD pointer */
 
	
 
	//  LIBXML_TEST_VERSION;
 
	
 
	/* 
 
	 * Creates a new document, a node and set it as a root node
 
	 */
 
	doc = xmlNewDoc(BAD_CAST "1.0");
 
	root_node = xmlNewNode(NULL, BAD_CAST "leaf");
 
	xmlDocSetRootElement(doc, root_node);
 
	
 
	/* 
 
	 * xmlNewProp() creates attributes, which is "attached" to an node.
 
	 * It returns xmlAttrPtr, which isn't used here.
 
	 */
 
	xmlNewProp(root_node, BAD_CAST "name", BAD_CAST docname);
 
	
 
	time_t t;
 
	std::time(&t);
 

	
 
  // based on libxml2 example code "tree2.c"
 

	
 
  xmlDocPtr doc = NULL;       /* document pointer */
 
  xmlNodePtr root_node = NULL;/* node pointers */
 
  //xmlDtdPtr dtd = NULL;       /* DTD pointer */
 

	
 
  //  LIBXML_TEST_VERSION;
 

	
 
  /* 
 
   * Creates a new document, a node and set it as a root node
 
   */
 
  doc = xmlNewDoc(BAD_CAST "1.0");
 
  root_node = xmlNewNode(NULL, BAD_CAST "leaf");
 
  xmlDocSetRootElement(doc, root_node);
 

	
 
  /* 
 
   * xmlNewProp() creates attributes, which is "attached" to an node.
 
   * It returns xmlAttrPtr, which isn't used here.
 
   */
 
  xmlNewProp(root_node, BAD_CAST "name", BAD_CAST docname);
 

	
 
  time_t t;
 
  std::time(&t);
 

	
 
  char *tstring = strdup(asctime(localtime(&t))); // but this does
 
  // replace "end of line character by '\0'
 
  char *eol=strchr(tstring,'\n');
 
  if (eol!=NULL)
 
    *eol='\0';
 

	
 
  xmlNewProp(root_node, BAD_CAST "date", BAD_CAST tstring);
 
  free(tstring);
 

	
 

	
 
	char *tstring = strdup(asctime(localtime(&t))); // but this does
 
	// replace "end of line character by '\0'
 
	char *eol=strchr(tstring,'\n');
 
	if (eol!=NULL)
 
		*eol='\0';
 
	
 
	xmlNewProp(root_node, BAD_CAST "date", BAD_CAST tstring);
 
	free(tstring);
 
	
 
	
 
	QString simtime = QString("%1").arg(time);
 
	xmlNewProp(root_node, BAD_CAST "simtime", BAD_CAST simtime.toStdString().c_str()); 
 
	/*
 
	 * Creates a DTD declaration. Isn't mandatory. 
 
	 */
 
  QString simtime = QString("%1").arg(time);
 
  xmlNewProp(root_node, BAD_CAST "simtime", BAD_CAST simtime.toStdString().c_str()); 
 
  /*
 
   * Creates a DTD declaration. Isn't mandatory. 
 
   */
 

	
 
  par.XMLAdd(root_node);
 

	
 
  xmlNodePtr xmlnodes = xmlNewChild(root_node, NULL, BAD_CAST "nodes",NULL);
 
  { ostringstream text;
 
    text << NNodes();
 
    xmlNewProp(xmlnodes, BAD_CAST "n", BAD_CAST text.str().c_str());
 
  }
 

	
 
  { ostringstream text;
 
    text << Node::target_length;
 
    xmlNewProp(xmlnodes, BAD_CAST "target_length", BAD_CAST text.str().c_str());
 
  }
 

	
 
	par.XMLAdd(root_node);
 
  for (vector<Node *>::const_iterator i=nodes.begin();
 
       i!=nodes.end();
 
       i++) {
 
    (*i)->XMLAdd(xmlnodes) ;
 
  }
 

	
 

	
 
  /* 
 
   * xmlNewChild() creates a new node, which is "attached" as child node
 
   * of root_node node. 
 
   */
 
  xmlNodePtr xmlcells = xmlNewChild(root_node, NULL, BAD_CAST "cells",NULL);
 
  {
 
    ostringstream text;
 
    text << NCells();
 
    xmlNewProp(xmlcells, BAD_CAST "n", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    ostringstream text;
 
    text << Cell::offset[0];
 
    xmlNewProp(xmlcells, BAD_CAST "offsetx", BAD_CAST text.str().c_str());
 
  }
 

	
 
	xmlNodePtr xmlnodes = xmlNewChild(root_node, NULL, BAD_CAST "nodes",NULL);
 
	{ ostringstream text;
 
		text << NNodes();
 
		xmlNewProp(xmlnodes, BAD_CAST "n", BAD_CAST text.str().c_str());
 
	}
 
	
 
	{ ostringstream text;
 
		text << Node::target_length;
 
		xmlNewProp(xmlnodes, BAD_CAST "target_length", BAD_CAST text.str().c_str());
 
	}
 
	
 
	
 
	
 
	for (vector<Node *>::const_iterator i=nodes.begin();
 
		 i!=nodes.end();
 
		 i++) {
 
		(*i)->XMLAdd(xmlnodes) ;
 
	}
 
	
 
	
 
	/* 
 
	 * xmlNewChild() creates a new node, which is "attached" as child node
 
	 * of root_node node. 
 
	 */
 
	xmlNodePtr xmlcells = xmlNewChild(root_node, NULL, BAD_CAST "cells",NULL);
 
	{
 
		ostringstream text;
 
		text << NCells();
 
		xmlNewProp(xmlcells, BAD_CAST "n", BAD_CAST text.str().c_str());
 
	}
 
	{
 
		ostringstream text;
 
		text << Cell::offset[0];
 
		xmlNewProp(xmlcells, BAD_CAST "offsetx", BAD_CAST text.str().c_str());
 
	}
 
	
 
	{
 
		ostringstream text;
 
		text << Cell::offset[1];
 
		xmlNewProp(xmlcells, BAD_CAST "offsety", BAD_CAST text.str().c_str());
 
	}
 
	
 
	{
 
		ostringstream text;
 
		text << Cell::factor;
 
		xmlNewProp(xmlcells, BAD_CAST "magnification", BAD_CAST text.str().c_str());
 
	}
 
	
 
	{
 
		ostringstream text;
 
		text << cells.front()->BaseArea();
 
		xmlNewProp(xmlcells, BAD_CAST "base_area", BAD_CAST text.str().c_str());
 
	}
 
	
 
	{ 
 
		ostringstream text;
 
		text << Cell::NChem();
 
		xmlNewProp(xmlcells, BAD_CAST "nchem", BAD_CAST text.str().c_str());
 
	}
 
	
 
	for (vector<Cell *>::const_iterator i=cells.begin();
 
		 i!=cells.end();
 
		 i++) {
 
		(*i)->XMLAdd(xmlcells) ;
 
	}
 
	
 
	boundary_polygon->XMLAdd(xmlcells);
 
	
 
	xmlNodePtr xmlwalls = xmlNewChild(root_node, NULL, BAD_CAST "walls",NULL);
 
	{ 
 
		ostringstream text;
 
		text << walls.size();
 
		xmlNewProp(xmlwalls, BAD_CAST "n", BAD_CAST text.str().c_str());
 
	}
 
	
 
	
 
	for (list<Wall *>::const_iterator i=walls.begin();
 
		 i!=walls.end();
 
		 i++) {
 
		(*i)->XMLAdd(xmlwalls) ;
 
	}
 
	
 
	
 
	xmlNodePtr xmlnodesets = xmlNewChild(root_node, NULL, BAD_CAST "nodesets",NULL);
 
	{ 
 
		ostringstream text;
 
		text << node_sets.size();
 
		xmlNewProp(xmlnodesets, BAD_CAST "n", BAD_CAST text.str().c_str());
 
	}
 
	
 
	
 
	for_each( node_sets.begin(), node_sets.end(), 
 
			 bind2nd ( 
 
					  mem_fun( &NodeSet::XMLAdd ),
 
					  xmlnodesets
 
					  ) );
 
	
 
	
 
	// Add option tree for interactive application
 
	if (options) {
 
		xmlAddChild(root_node, options);
 
	}
 
	
 
	
 
	
 
	
 
	/* 
 
	 * Dumping document to stdio or file
 
	 */
 
	xmlSetDocCompressMode(doc,9);
 
	xmlSaveFormatFileEnc(docname, doc, "UTF-8", 1);
 
	
 
	/*free the document */
 
	xmlFreeDoc(doc);
 
	
 
	/*
 
	 *Free the global variables that may
 
	 *have been allocated by the parser.
 
	 */
 
	xmlCleanupParser();
 
	
 
	/*
 
	 * this is to debug memory for regression tests
 
	 */
 
  {
 
    ostringstream text;
 
    text << Cell::offset[1];
 
    xmlNewProp(xmlcells, BAD_CAST "offsety", BAD_CAST text.str().c_str());
 
  }
 

	
 
  {
 
    ostringstream text;
 
    text << Cell::factor;
 
    xmlNewProp(xmlcells, BAD_CAST "magnification", BAD_CAST text.str().c_str());
 
  }
 

	
 
  {
 
    ostringstream text;
 
    text << cells.front()->BaseArea();
 
    xmlNewProp(xmlcells, BAD_CAST "base_area", BAD_CAST text.str().c_str());
 
  }
 

	
 
  { 
 
    ostringstream text;
 
    text << Cell::NChem();
 
    xmlNewProp(xmlcells, BAD_CAST "nchem", BAD_CAST text.str().c_str());
 
  }
 

	
 
  for (vector<Cell *>::const_iterator i=cells.begin();
 
       i!=cells.end();
 
       i++) {
 
    (*i)->XMLAdd(xmlcells) ;
 
  }
 

	
 
  boundary_polygon->XMLAdd(xmlcells);
 

	
 
  xmlNodePtr xmlwalls = xmlNewChild(root_node, NULL, BAD_CAST "walls",NULL);
 
  { 
 
    ostringstream text;
 
    text << walls.size();
 
    xmlNewProp(xmlwalls, BAD_CAST "n", BAD_CAST text.str().c_str());
 
  }
 

	
 

	
 
  for (list<Wall *>::const_iterator i=walls.begin();
 
       i!=walls.end();
 
       i++) {
 
    (*i)->XMLAdd(xmlwalls) ;
 
  }
 

	
 

	
 
  xmlNodePtr xmlnodesets = xmlNewChild(root_node, NULL, BAD_CAST "nodesets",NULL);
 
  { 
 
    ostringstream text;
 
    text << node_sets.size();
 
    xmlNewProp(xmlnodesets, BAD_CAST "n", BAD_CAST text.str().c_str());
 
  }
 

	
 
  for_each( node_sets.begin(), node_sets.end(), bind2nd ( mem_fun( &NodeSet::XMLAdd ), xmlnodesets ) );
 

	
 
  // Add option tree for interactive application
 
  if (options) {
 
    xmlAddChild(root_node, options);
 
  }
 

	
 

	
 
  /* 
 
   * Dumping document to stdio or file
 
   */
 
  xmlSetDocCompressMode(doc,9);
 
  xmlSaveFormatFileEnc(docname, doc, "UTF-8", 1);
 

	
 
  /*free the document */
 
  xmlFreeDoc(doc);
 

	
 
  /*
 
   *Free the global variables that may
 
   *have been allocated by the parser.
 
   */
 
  xmlCleanupParser();
 

	
 
  /*
 
   * this is to debug memory for regression tests
 
   */
 
}
 

	
 

	
 

	
 
void Mesh::XMLReadSimtime(const xmlNode *a_node) {
 
	
 
void Mesh::XMLReadSimtime(const xmlNode *a_node)
 
{
 

	
 
  xmlNode *root_node;
 
  root_node = (xmlNode *)a_node;
 
  xmlChar *strsimtime = xmlGetProp(root_node, BAD_CAST "simtime");
 
  
 
  
 

	
 

	
 
  if (strsimtime) {
 

	
 
    QLocale standardlocale(QLocale::C);
 
    bool ok;
 
    
 

	
 
    double simtime=standardlocale.toDouble((char *)strsimtime, &ok);
 
    if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(char *)strsimtime);
 
      time = simtime;
 
    time = simtime;
 
#ifdef QDEBUG
 
                qDebug() << "Simtime = " << strsimtime << endl;
 
    qDebug() << "Simtime = " << strsimtime << endl;
 
#endif
 
	} else {
 
  } else {
 
#ifdef QDEBUG
 
    qDebug() << "No simtime found in file." << endl;
 
#endif
 
		time =0;
 
	}	
 
    time =0;
 
  }	
 
}
 

	
 
void Mesh::XMLReadPars(const xmlNode * a_node) {
 
	xmlNode *root_node;
 
	root_node = (xmlNode *)a_node;
 
	par.XMLRead(root_node);
 
	Seed(par.rseed);
 
	MakeDir(par.datadir);
 
void Mesh::XMLReadPars(const xmlNode * a_node)
 
{
 
  xmlNode *root_node;
 
  root_node = (xmlNode *)a_node;
 
  par.XMLRead(root_node);
 
  Seed(par.rseed);
 
  MakeDir(par.datadir);
 
}
 

	
 
void Mesh::XMLReadGeometry(const xmlNode * a_node)
 
{
 
  
 
	xmlNode *root_node;
 
	root_node = (xmlNode *)a_node;
 
	xmlNode *cur;
 
	QLocale standardlocale(QLocale::C);
 
	bool ok;
 
	// allocate Nodes
 
	cur = root_node->xmlChildrenNode;
 
	while (cur!=NULL) {
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"nodes"))){
 
			XMLReadNodes(cur);
 
		}
 
		cur=cur->next;
 
	}
 
	
 
	cur = root_node->xmlChildrenNode;
 
	while (cur!=NULL) {
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"nodesets"))) {
 
			XMLReadNodeSets(cur);
 
		}
 
		cur=cur->next;
 
	}
 
	
 
	cur=root_node->xmlChildrenNode;
 
	while (cur!=NULL) {
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"nodes"))) {
 
			XMLReadNodeSetsToNodes(cur);
 
		}
 
		cur = cur->next;
 
	}
 
    
 
    
 
	// allocate Cells
 
	cur = root_node;
 
	
 
	// allocate Cells
 
	cur = cur->xmlChildrenNode;
 
	while (cur!=NULL) {
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"cells"))){
 
			xmlChar *offsetxc = xmlGetProp(cur, BAD_CAST "offsetx");
 
			xmlChar *offsetyc = xmlGetProp(cur, BAD_CAST "offsety");
 

	
 
  xmlNode *root_node;
 
  root_node = (xmlNode *)a_node;
 
  xmlNode *cur;
 
  QLocale standardlocale(QLocale::C);
 
  bool ok;
 
  // allocate Nodes
 
  cur = root_node->xmlChildrenNode;
 
  while (cur!=NULL) {
 
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"nodes"))){
 
      XMLReadNodes(cur);
 
    }
 
    cur=cur->next;
 
  }
 

	
 
  cur = root_node->xmlChildrenNode;
 
  while (cur!=NULL) {
 
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"nodesets"))) {
 
      XMLReadNodeSets(cur);
 
    }
 
    cur=cur->next;
 
  }
 

	
 
			double ox=standardlocale.toDouble((const char *)offsetxc, &ok);
 
			if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)offsetxc);
 
  cur=root_node->xmlChildrenNode;
 
  while (cur!=NULL) {
 
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"nodes"))) {
 
      XMLReadNodeSetsToNodes(cur);
 
    }
 
    cur = cur->next;
 
  }
 

	
 

	
 
  // allocate Cells
 
  cur = root_node;
 

	
 
			double oy=standardlocale.toDouble((const char *)offsetyc, &ok);
 
			if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)offsetyc);
 
			Cell::setOffset(ox, oy);
 
			xmlFree(offsetxc);
 
			xmlFree(offsetyc);
 
			
 
			xmlChar *magnificationc = xmlGetProp(cur, BAD_CAST "magnification");
 
  // allocate Cells
 
  cur = cur->xmlChildrenNode;
 
  while (cur!=NULL) {
 
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"cells"))){
 
      xmlChar *offsetxc = xmlGetProp(cur, BAD_CAST "offsetx");
 
      xmlChar *offsetyc = xmlGetProp(cur, BAD_CAST "offsety");
 

	
 
      double ox=standardlocale.toDouble((const char *)offsetxc, &ok);
 
      if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)offsetxc);
 

	
 
      double oy=standardlocale.toDouble((const char *)offsetyc, &ok);
 
      if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)offsetyc);
 
      Cell::setOffset(ox, oy);
 
      xmlFree(offsetxc);
 
      xmlFree(offsetyc);
 

	
 
			Cell::SetMagnification(standardlocale.toDouble((const char *)magnificationc, &ok));
 
			if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)magnificationc);
 
			xmlFree(magnificationc);
 
			
 
			xmlChar *baseareac = xmlGetProp(cur, BAD_CAST "base_area");
 
      xmlChar *magnificationc = xmlGetProp(cur, BAD_CAST "magnification");
 

	
 
      Cell::SetMagnification(standardlocale.toDouble((const char *)magnificationc, &ok));
 
      if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)magnificationc);
 
      xmlFree(magnificationc);
 

	
 
      xmlChar *baseareac = xmlGetProp(cur, BAD_CAST "base_area");
 

	
 
      Cell::BaseArea() = standardlocale.toDouble((const char *)baseareac, &ok);
 
      if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)baseareac);
 
      xmlFree(baseareac);
 

	
 
      XMLReadCells(cur);
 
    }
 
    cur=cur->next;
 
  }
 

	
 
  // allocate Walls (we need to have read the cells before constructing walls)
 
  vector <Wall *> tmp_walls;
 
  cur = root_node->xmlChildrenNode;
 
  while (cur!=NULL) {
 
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"walls"))){
 
      XMLReadWalls(cur, &tmp_walls);
 
    }
 
    cur=cur->next;
 
  }
 

	
 
			Cell::BaseArea() = standardlocale.toDouble((const char *)baseareac, &ok);
 
			if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)baseareac);
 
			xmlFree(baseareac);
 
			
 
			
 
			XMLReadCells(cur);
 
		}
 
		cur=cur->next;
 
	}
 
    
 
	// allocate Walls (we need to have read the cells before constructing walls)
 
	vector <Wall *> tmp_walls;
 
	cur = root_node->xmlChildrenNode;
 
	while (cur!=NULL) {
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"walls"))){
 
			XMLReadWalls(cur, &tmp_walls);
 
		}
 
		cur=cur->next;
 
	}
 
	
 
	// read walls to cells and boundary_polygon
 
	cur = root_node->xmlChildrenNode;
 
	while (cur!=NULL) {
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"cells"))) {
 
			XMLReadWallsToCells(cur, &tmp_walls);
 
		}
 
		cur=cur->next;
 
	}
 
    
 
	boundary_polygon->ConstructNeighborList();
 
	boundary_polygon->ConstructConnections();
 
	
 
	for (vector<Cell *>::iterator c=cells.begin();
 
		 c!=cells.end();
 
		 c++) {
 
		
 
		(*c)->ConstructNeighborList();
 
		(*c)->ConstructConnections();
 
		
 
	}
 
	
 
	shuffled_cells.clear();
 
	shuffled_cells = cells;
 
	
 
	MyUrand r(shuffled_cells.size());
 
	random_shuffle(shuffled_cells.begin(),shuffled_cells.end(),r);
 
    
 
  // read walls to cells and boundary_polygon
 
  cur = root_node->xmlChildrenNode;
 
  while (cur!=NULL) {
 
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"cells"))) {
 
      XMLReadWallsToCells(cur, &tmp_walls);
 
    }
 
    cur=cur->next;
 
  }
 

	
 
  boundary_polygon->ConstructNeighborList();
 
  boundary_polygon->ConstructConnections();
 

	
 
  for (vector<Cell *>::iterator c=cells.begin();
 
       c!=cells.end();
 
       c++) {
 

	
 
    (*c)->ConstructNeighborList();
 
    (*c)->ConstructConnections();
 

	
 
  }
 

	
 
  shuffled_cells.clear();
 
  shuffled_cells = cells;
 

	
 
  MyUrand r(shuffled_cells.size());
 
  random_shuffle(shuffled_cells.begin(),shuffled_cells.end(),r);
 
}
 

	
 
void Mesh::XMLParseTree(const xmlNode *root_node) {
 
	
 
	XMLReadSimtime(root_node);
 
	XMLReadPars(root_node);
 
	XMLReadGeometry(root_node);
 
	
 
void Mesh::XMLParseTree(const xmlNode *root_node)
 
{
 
  XMLReadSimtime(root_node);
 
  XMLReadPars(root_node);
 
  XMLReadGeometry(root_node);
 
}
 

	
 

	
 
void Mesh::XMLReadNodes(xmlNode *root) {
 
	
 
void Mesh::XMLReadNodes(xmlNode *root)
 
{
 

	
 
  QLocale standardlocale(QLocale::C);
 
  bool ok;
 

	
 
  xmlNode *cur = root;
 
  cur = cur->xmlChildrenNode;
 
	
 

	
 
  for (vector<Node *>::iterator i=nodes.begin();
 
       i!=nodes.end();
 
       i++) {
 
    delete *i;
 
  }
 
	
 

	
 
  nodes.clear();
 
  Node::nnodes=0;
 
	
 

	
 
  xmlChar *tlc = xmlGetProp(root, BAD_CAST "target_length");
 
	
 

	
 
  if (tlc != 0) {
 

	
 
	  
 
    Node::target_length = standardlocale.toDouble((const char *)tlc, &ok);
 
    if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)tlc);
 
		
 

	
 
    xmlFree(tlc);
 
  } else {
 
    // note that libxml2 also defines a token "warning"
 
    MyWarning::unique_warning("Warning: value found in XML file for Node::target_length.");
 
  }
 
    
 

	
 
  while (cur!=NULL) {
 
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"node"))){
 
			
 

	
 
      xmlChar *xc = xmlGetProp(cur, BAD_CAST "x");
 
			
 

	
 
      if (xc==0) {
 
	unique_warning("Token \"x\" not found in xmlwrite.cpp at or around line no. 722");
 
      }
 
			
 

	
 
      xmlChar *yc = xmlGetProp(cur, BAD_CAST "y");
 
			
 

	
 
      if (yc==0) {
 
	unique_warning("Token \"y\" not found in xmlwrite.cpp at or around line no. 727");
 
      }
 
			
 

	
 
      xmlChar *fixedc = xmlGetProp(cur, BAD_CAST "fixed");
 
      if (fixedc==0) {
 
	unique_warning("Token \"fixed\" not found in xmlwrite.cpp at or around line.");
 
      }
 
			
 

	
 
      xmlChar *boundaryc = xmlGetProp(cur, BAD_CAST "boundary");
 
      if (boundaryc==0) {
 
	unique_warning("Token \"boundary\" not found in xmlwrite.cpp at or around line.");
 
      }
 
			
 

	
 
      xmlChar *samc = xmlGetProp(cur, BAD_CAST "sam");
 
      if (samc==0) {
 
	unique_warning("Token \"sam\" not found in xmlwrite.cpp at or around line.");
 
      }
 
			
 

	
 

	
 
      double x = standardlocale.toDouble((const char *)xc, &ok);
 
      if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)xc);
 
		
 

	
 
      double y = standardlocale.toDouble((const char *)yc, &ok);
 
      if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)yc);
 
			
 

	
 
      Node *new_node = new Node(x,y);
 
      nodes.push_back(new_node);
 
			
 

	
 
      new_node->m = this;
 
      new_node->fixed = strtobool( (char *)fixedc);
 
      new_node->boundary = strtobool( (char *)boundaryc );
 
      new_node->sam = strtobool ( (char *)samc);
 
      new_node->node_set = 0;
 
			
 

	
 
      xmlFree(xc);
 
      xmlFree(yc);
 
      xmlFree(boundaryc);
 
      xmlFree(fixedc);
 
      xmlFree(samc);
 
			
 
			
 
    }
 
    cur=cur->next;
 
  }
 
	
 

	
 
  shuffled_nodes.clear();
 
  shuffled_nodes = nodes;
 
	
 

	
 
  MyUrand r(shuffled_nodes.size());
 
  random_shuffle(shuffled_nodes.begin(),shuffled_nodes.end(),r);
 
	
 
}
 

	
 
void Mesh::XMLReadWalls(xmlNode *root, vector<Wall *> *tmp_walls) {
 
	
 
void Mesh::XMLReadWalls(xmlNode *root, vector<Wall *> *tmp_walls)
 
{
 

	
 
  xmlNode *cur = root;
 
  cur = cur->xmlChildrenNode;
 
	
 

	
 
  for (list<Wall *>::iterator i=walls.begin();
 
       i!=walls.end();
 
       i++) {
 
    delete *i;
 
  }
 
	
 

	
 
  walls.clear();
 
  Wall::nwalls = 0;
 
  tmp_walls->clear();
 
	
 

	
 
  QLocale standardlocale(QLocale::C);
 
  bool ok;
 

	
 
  while (cur!=NULL) {
 
		
 

	
 
    vector<int> tmp_nodes;
 
    while(cur!=NULL) {
 
      if ((!xmlStrcmp(cur->name, (const xmlChar *)"wall"))) {
 
				
 

	
 
	xmlChar *nc = xmlGetProp(cur, BAD_CAST "c1");
 
				
 

	
 
	if (nc==0) {
 
	  unique_warning("Token \"c1\" not found in xmlwrite.cpp at or around line no. 777");
 
	}
 
	int c1 = atoi( (char *)nc);
 
	xmlFree(nc);
 
				
 

	
 
	nc = xmlGetProp(cur, BAD_CAST "c2");
 
				
 

	
 
	if (	nc==0) {
 
	  unique_warning("Token \"c2\" not found in xmlwrite.cpp at or around line no. 785");
 
	}
 
	int c2 = atoi( (char *)nc);
 
	xmlFree(nc);
 
				
 

	
 
	nc = xmlGetProp(cur, BAD_CAST "n1");
 
				
 

	
 
	if (	nc==0) {
 
	  unique_warning("Token \"n1\" not found in xmlwrite.cpp at or around line no. 793");
 
	}
 
	int n1 = atoi( (char *)nc);
 
	xmlFree(nc);
 
				
 

	
 
	nc = xmlGetProp(cur, BAD_CAST "n2");
 
				
 

	
 
	if (	nc==0) {
 
	  unique_warning("Token \"n2\" not found in xmlwrite.cpp at or around line no. 801");
 
	}
 
	int n2 = atoi( (char *)nc);
 
	xmlFree(nc);
 
				
 

	
 
	nc = xmlGetProp(cur, BAD_CAST "length");
 
				
 

	
 
	if (	nc==0) {
 
	  unique_warning("Token \"length\" not found in xmlwrite.cpp at or around line no. 809");
 
	}
 

	
 
	double length = standardlocale.toDouble((const char *)nc, &ok);
 
	if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)nc);
 

	
 
	xmlFree(nc);
 
				
 
				
 

	
 

	
 
	nc = xmlGetProp(cur, BAD_CAST "viz_flux");
 
				
 

	
 
	double viz_flux = 0.0;
 
	if (nc!=0) {
 

	
 
	  viz_flux = standardlocale.toDouble((const char *)nc, &ok);
 
	  if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)nc);
 
	}
 
	xmlFree(nc);
 
				
 

	
 
	Wall::WallType wall_type;
 
	{
 
	  xmlChar *v_str = xmlGetProp(cur, BAD_CAST "wall_type");
 
					
 

	
 
	  if (v_str != 0) {
 
						
 

	
 
	    if (!xmlStrcmp(v_str, (const xmlChar *)"aux_source")) {
 
	      wall_type = Wall::AuxSource;
 
	    } else {
 
	      if (!xmlStrcmp(v_str, (const xmlChar *)"aux_sink")) {
 
		wall_type = Wall::AuxSink;
 
	      } else {
 
		wall_type = Wall::Normal;
 
	      }
 
	    }
 
	    xmlFree(v_str);
 
						
 

	
 
	  } else {
 
	    wall_type = Wall::Normal;
 
	  }
 
	}
 
				
 

	
 
	bool dead = false;
 
	{
 
	  // Note: property "delete" is used to manually clean up wall lists in XML files
 
	  // Simply add property 'delete="true"' to the wall and it will be removed from
 
	  // the mesh. (This saves us from manually reindexing the file). Otherwise do not use it.
 
	  xmlChar *v_str = xmlGetProp(cur, BAD_CAST "delete");
 
					
 

	
 
	  if (v_str != 0) {
 
	    dead = strtobool( (char *)v_str);
 
	    xmlFree(v_str);
 
	  }
 
					
 
	}
 
				
 

	
 
	Cell *cc1 = c1 != -1 ? cells[c1] : boundary_polygon;
 
	Cell *cc2 = c2 != -1 ? cells[c2] : boundary_polygon;
 
				
 

	
 
	Wall *w = new Wall( nodes[n1], nodes[n2], cc1, cc2);
 
	w->length = length;
 
	w->viz_flux = viz_flux;
 
	w->wall_type = wall_type;
 
	w->dead = dead;
 
	tmp_walls->push_back(w);
 
	walls.push_back(w);
 
				
 

	
 
	xmlNode *w_node = cur->xmlChildrenNode;
 
	while (w_node!=NULL) {
 
	  if ((!xmlStrcmp(w_node->name, (const xmlChar *)"transporters1"))) {
 
						
 

	
 
	    xmlNode *v_node = w_node->xmlChildrenNode;
 
	    int nv=0;
 
	    while (v_node!=NULL) {
 
							
 

	
 
	      if ((!xmlStrcmp(v_node->name, (const xmlChar *)"val"))) {
 
		if (nv>=Cell::NChem()) {
 
		  {
 
		    stringstream text;
 
		    text << "Exception in Mesh::XMLRead: Too many transporter values given for wall(s). Ignoring remaining values.";
 

	
 
		    unique_warning(text.str().c_str());
 
		    break;
 
		  }
 
		}
 
		xmlChar *nc = xmlGetProp(v_node, (const xmlChar *) "v");
 
								
 

	
 
		if (nc==0) {
 
		  unique_warning("Token \"v\" not found in xmlwrite.cpp at or around line no. 835");
 
		}
 

	
 
		double v = standardlocale.toDouble((const char *)nc, &ok);
 
		if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)nc);
 

	
 
		w->transporters1[nv++]=v;
 
		xmlFree(nc);
 
								
 

	
 
	      }
 
	      v_node = v_node->next; 
 
	    }
 
						
 
	  }
 
					
 
					
 

	
 
	  if ((!xmlStrcmp(w_node->name, (const xmlChar *)"transporters2"))) {
 
						
 

	
 
	    xmlNode *v_node = w_node->xmlChildrenNode;
 
	    int nv=0;
 
	    while (v_node!=NULL) {
 
	      if ((!xmlStrcmp(v_node->name, (const xmlChar *)"val"))) {
 
		if (nv>=Cell::NChem()) {
 
		  {
 
		    stringstream text;
 
		    text << "Exception in Mesh::XMLRead: Too many transporter values given for wall(s). Ignoring remaining values.";
 
		    unique_warning(text.str().c_str());
 
		    break;
 

	
 
		  }
 
		}
 
								
 

	
 
		xmlChar *nc = xmlGetProp(v_node, (const xmlChar *) "v");
 
								
 

	
 
		if (nc==0) {
 
		  unique_warning("Token \"v\" not found in xmlwrite.cpp at or around line no. 861");
 
		}
 

	
 
		double v = standardlocale.toDouble((const char *)nc, &ok);
 
		if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)nc);
 

	
 
		w->transporters2[nv++]=v;
 
		xmlFree(nc);
 
	      }
 
	      v_node = v_node->next; 
 
	    }
 
						
 
	  } 
 
					
 

	
 
	  if ((!xmlStrcmp(w_node->name, (const xmlChar *)"apoplast"))) {
 
						
 

	
 
	    xmlNode *v_node = w_node->xmlChildrenNode;
 
	    int nv=0;
 
	    while (v_node!=NULL) {
 
							
 

	
 
	      if ((!xmlStrcmp(v_node->name, (const xmlChar *)"val"))) {
 
		if (nv>=Cell::NChem()) {
 
		  {
 
		    stringstream text;
 
		    text << "Exception in Mesh::XMLRead: Too many transporter values given for wall(s). Ignoring remaining values.";
 

	
 
		    unique_warning(text.str().c_str());
 
		    break;
 
		  }
 
		}
 
		xmlChar *nc = xmlGetProp(v_node, (const xmlChar *) "v");
 
								
 

	
 
		if (nc==0) {
 
		  unique_warning("Token \"v\" not found in xmlwrite.cpp at or around line no. 887");
 
		}
 

	
 
		double v = standardlocale.toDouble((const char *)nc, &ok);
 
		if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)nc);
 

	
 
		w->apoplast[nv++]=v;
 
		xmlFree(nc);
 
	      }
 
	      v_node = v_node->next; 
 
	    }
 
	  }
 
	  w_node=w_node->next;
 
	}
 
      }
 
      cur = cur->next;
 
    }
 
  }
 
}
 

	
 

	
 
void Mesh::XMLReadWallsToCells(xmlNode *root, vector<Wall *> *tmp_walls) {
 
	
 
	// Add the walls to the cells (do this after reading the walls; read walls after reading cells...)
 
	// 1. Read Nodes
 
	// 2. Read Cells
 
	// 3. Read Walls
 
	// 4. Read Walls into Cells
 
	
 
	xmlNode *cur = root->xmlChildrenNode;
 
	int ci=0; // cell index
 
	
 
	while (cur!=NULL) {
 
		
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"cell")) ||
 
			(!xmlStrcmp(cur->name, (const xmlChar *)"boundary_polygon" ))) {
 
			
 
			vector<int> tmp_walls_ind;
 
			xmlNode *n = cur->xmlChildrenNode;
 
			
 
			while(n!=NULL) {
 
				
 
				if ((!xmlStrcmp(n->name, (const xmlChar *)"wall"))) {
 
					xmlChar *nc = xmlGetProp(n, BAD_CAST "w");
 
					
 
					if (nc==0) {
 
						unique_warning("Token \"w\" not found in xmlwrite.cpp at or around line no. 931");
 
					}
 
					tmp_walls_ind.push_back(atoi( (char *)nc));
 
					xmlFree(nc);
 
				}
 
				n = n->next;
 
			}
 
			
 
			if (!xmlStrcmp(cur->name, (const xmlChar *)"boundary_polygon")) {
 
				
 
				int nwalls = tmp_walls_ind.size();
 
				for (int i=0;i<nwalls;i++) {
 
					boundary_polygon->walls.push_back((*tmp_walls)[tmp_walls_ind[i]]);
 
				}
 
			} else {
 
				
 
				int nwalls = tmp_walls_ind.size();
 
				for (int i=0;i<nwalls;i++) {
 
					cells[ci]->walls.push_back((*tmp_walls)[tmp_walls_ind[i]]);	
 
				}
 
				
 
				ci++;
 
			}
 
			
 
		} 
 
		cur=cur->next;
 
void Mesh::XMLReadWallsToCells(xmlNode *root, vector<Wall *> *tmp_walls)
 
{
 

	
 
  // Add the walls to the cells (do this after reading the walls; read walls after reading cells...)
 
  // 1. Read Nodes
 
  // 2. Read Cells
 
  // 3. Read Walls
 
  // 4. Read Walls into Cells
 

	
 
  xmlNode *cur = root->xmlChildrenNode;
 
  int ci=0; // cell index
 

	
 
  while (cur!=NULL) {
 

	
 
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"cell")) ||
 
	(!xmlStrcmp(cur->name, (const xmlChar *)"boundary_polygon" ))) {
 

	
 
      vector<int> tmp_walls_ind;
 
      xmlNode *n = cur->xmlChildrenNode;
 

	
 
      while(n!=NULL) {
 

	
 
	if ((!xmlStrcmp(n->name, (const xmlChar *)"wall"))) {
 
	  xmlChar *nc = xmlGetProp(n, BAD_CAST "w");
 

	
 
	  if (nc==0) {
 
	    unique_warning("Token \"w\" not found in xmlwrite.cpp at or around line no. 931");
 
	  }
 
	  tmp_walls_ind.push_back(atoi( (char *)nc));
 
	  xmlFree(nc);
 
	}
 
	
 
	
 
	n = n->next;
 
      }
 

	
 
      if (!xmlStrcmp(cur->name, (const xmlChar *)"boundary_polygon")) {
 

	
 
	int nwalls = tmp_walls_ind.size();
 
	for (int i=0;i<nwalls;i++) {
 
	  boundary_polygon->walls.push_back((*tmp_walls)[tmp_walls_ind[i]]);
 
	}
 
      } else {
 

	
 
	int nwalls = tmp_walls_ind.size();
 
	for (int i=0;i<nwalls;i++) {
 
	  cells[ci]->walls.push_back((*tmp_walls)[tmp_walls_ind[i]]);	
 
	}
 
	ci++;
 
      }
 
    } 
 
    cur=cur->next;
 
  }
 
}
 

	
 

	
 
void Mesh::XMLReadNodeSetsToNodes(xmlNode *root) {
 
	
 
	xmlNode *cur = root->xmlChildrenNode;
 
	int ci=0; // cell index
 
	
 
	while (cur!=NULL) {
 
		
 
		
 
		
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"node"))) {
 
			
 
			xmlNode *n = cur->xmlChildrenNode;
 
			
 
			while(n!=NULL) {
 
				
 
				xmlChar *nc = xmlGetProp(n, BAD_CAST "nodeset");
 
				
 
				if (nc!=0) {
 
					int nodeset_n = atoi( (char *)nc);
 
					nodes[ci]->node_set = node_sets[nodeset_n];
 
					xmlFree(nc);
 
				} else {
 
					nodes[ci]->node_set = 0;
 
				}
 
				
 
				n = n->next;
 
			}
 
			
 
			ci++;
 
			
 
		} 
 
		cur=cur->next;
 
void Mesh::XMLReadNodeSetsToNodes(xmlNode *root)
 
{
 

	
 
  xmlNode *cur = root->xmlChildrenNode;
 
  int ci=0; // cell index
 

	
 
  while (cur!=NULL) {
 

	
 

	
 

	
 
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"node"))) {
 

	
 
      xmlNode *n = cur->xmlChildrenNode;
 

	
 
      while(n!=NULL) {
 

	
 
	xmlChar *nc = xmlGetProp(n, BAD_CAST "nodeset");
 

	
 
	if (nc!=0) {
 
	  int nodeset_n = atoi( (char *)nc);
 
	  nodes[ci]->node_set = node_sets[nodeset_n];
 
	  xmlFree(nc);
 
	} else {
 
	  nodes[ci]->node_set = 0;
 
	}
 
	
 
	
 

	
 
	n = n->next;
 
      }
 
      ci++;
 
    } 
 
    cur=cur->next;
 
  }
 
}
 

	
 

	
 
void Mesh::XMLReadNodeSets(xmlNode *root) {
 
	
 
	for (vector<NodeSet *>::iterator i=node_sets.begin();
 
		 i!=node_sets.end();
 
		 i++) {
 
		delete *i;
 
	}
 
	
 
	node_sets.clear();
 
	
 
	xmlNode *cur = root->xmlChildrenNode;
 
	
 
	while (cur!=NULL) {
 
		
 
		NodeSet *new_nodeset=0;
 
		
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"nodeset"))){
 
			new_nodeset = new NodeSet();
 
			node_sets.push_back(new_nodeset);
 
		} 
 
		
 
		if (new_nodeset == 0) { 
 
			cur = cur->next;
 
			continue;
 
		}
 
		new_nodeset->XMLRead(cur, this);
 
		cur=cur->next;
 
	}
 
	
 
void Mesh::XMLReadNodeSets(xmlNode *root)
 
{
 

	
 
  for (vector<NodeSet *>::iterator i=node_sets.begin();
 
       i!=node_sets.end();
 
       i++) {
 
    delete *i;
 
  }
 

	
 
  node_sets.clear();
 

	
 
  xmlNode *cur = root->xmlChildrenNode;
 

	
 
  while (cur!=NULL) {
 

	
 
    NodeSet *new_nodeset=0;
 

	
 
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"nodeset"))){
 
      new_nodeset = new NodeSet();
 
      node_sets.push_back(new_nodeset);
 
    } 
 

	
 
    if (new_nodeset == 0) { 
 
      cur = cur->next;
 
      continue;
 
    }
 
    new_nodeset->XMLRead(cur, this);
 
    cur=cur->next;
 
  }
 
}
 

	
 
void Mesh::XMLReadCells(xmlNode *root) {
 
	
 
	for (vector<Cell *>::iterator i=cells.begin();
 
		 i!=cells.end();
 
		 i++) {
 
		delete *i;
 
	}
 
	
 
	cells.clear();
 
	Cell::NCells() = 0;
 
	
 
	delete boundary_polygon;
 
	
 
	
 
	xmlNode *cur = root->xmlChildrenNode;
 
	
 
	while (cur!=NULL) {
 
		
 
		Cell *new_cell=0;
 
void Mesh::XMLReadCells(xmlNode *root)
 
{
 

	
 
  for (vector<Cell *>::iterator i=cells.begin();
 
       i!=cells.end();
 
       i++) {
 
    delete *i;
 
  }
 

	
 
  cells.clear();
 
  Cell::NCells() = 0;
 

	
 
  delete boundary_polygon;
 

	
 

	
 
  xmlNode *cur = root->xmlChildrenNode;
 

	
 
  while (cur!=NULL) {
 

	
 
    Cell *new_cell=0;
 

	
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"cell"))){
 
			
 
			new_cell = new Cell(0,0);
 
			new_cell->m = this;
 
			cells.push_back(new_cell);
 
		} else {
 
			if ((!xmlStrcmp(cur->name, (const xmlChar *)"boundary_polygon"))) {
 
				new_cell = boundary_polygon = new BoundaryPolygon(0,0);
 
				boundary_polygon->m = this;
 
			}
 
		}
 
		
 
		if (new_cell == 0) { 
 
			cur = cur->next;
 
			continue;
 
		}
 
		
 
		new_cell->XMLRead(cur);
 
		cur=cur->next;
 
	}
 
	
 
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"cell"))){
 

	
 
      new_cell = new Cell(0,0);
 
      new_cell->m = this;
 
      cells.push_back(new_cell);
 
    } else {
 
      if ((!xmlStrcmp(cur->name, (const xmlChar *)"boundary_polygon"))) {
 
	new_cell = boundary_polygon = new BoundaryPolygon(0,0);
 
	boundary_polygon->m = this;
 
      }
 
    }
 

	
 
    if (new_cell == 0) { 
 
      cur = cur->next;
 
      continue;
 
    }
 

	
 
    new_cell->XMLRead(cur);
 
    cur=cur->next;
 
  }
 
}
 

	
 
void Mesh::XMLRead(const char *docname, xmlNode **settings, bool geometry, bool pars, bool simtime) {
 
	
 
	xmlDocPtr doc = xmlParseFile(docname);
 
	if (doc == NULL ) {
 
		throw("Document not parsed successfully.");
 
		return;
 
	}
 
	
 
	xmlNodePtr cur = xmlDocGetRootElement(doc);
 
	
 
	if (cur == NULL) {
 
		throw("Document is empty");
 
		xmlFreeDoc(doc);
 
		return;
 
	}
 
	
 
	if (xmlStrcmp(cur->name, (const xmlChar *) "leaf")) {
 
		throw("XML file of the wrong type, it is not a leaf.");
 
		xmlFreeDoc(doc);
 
		return;
 
	}
 
	
 
	/*Get the root element node */
 
	xmlNode *root_element = xmlDocGetRootElement(doc);
 
void Mesh::XMLRead(const char *docname, xmlNode **settings, bool geometry, bool pars, bool simtime)
 
{
 

	
 
  xmlDocPtr doc = xmlParseFile(docname);
 
  if (doc == NULL ) {
 
    throw("Document not parsed successfully.");
 
    return;
 
  }
 

	
 
  xmlNodePtr cur = xmlDocGetRootElement(doc);
 

	
 
  if (cur == NULL) {
 
    throw("Document is empty");
 
    xmlFreeDoc(doc);
 
    return;
 
  }
 

	
 
  if (xmlStrcmp(cur->name, (const xmlChar *) "leaf")) {
 
    throw("XML file of the wrong type, it is not a leaf.");
 
    xmlFreeDoc(doc);
 
    return;
 
  }
 

	
 
  /*Get the root element node */
 
  xmlNode *root_element = xmlDocGetRootElement(doc);
 

	
 
	if (geometry) XMLReadGeometry(root_element);
 
	if (pars) XMLReadPars(root_element);
 
	if (simtime) XMLReadSimtime(root_element);
 
	
 
	// If pointer settings defined, return a copy of the settings tree
 
	if (settings) {
 
		xmlNode *cur = root_element->xmlChildrenNode;
 
		// if settings field is not found, *settings will be returned 0.
 
		*settings = 0;
 
		while (cur!=NULL) {
 
			if ((!xmlStrcmp(cur->name, (const xmlChar *)"settings"))){
 
				*settings = xmlCopyNode(cur,1);
 
			}
 
			cur=cur->next;
 
		}
 
	}
 
	xmlFreeDoc(doc);
 
	
 
	/*
 
	 *Free the global variables that may
 
	 *have been allocated by the parser.
 
	 */
 
	xmlCleanupParser();
 
	
 
	// We're doing this so we can manually delete walls with by adding the 'delete="true"' property
 
	CleanUpCellNodeLists();
 
	
 
  if (geometry) XMLReadGeometry(root_element);
 
  if (pars) XMLReadPars(root_element);
 
  if (simtime) XMLReadSimtime(root_element);
 

	
 
  // If pointer settings defined, return a copy of the settings tree
 
  if (settings) {
 
    xmlNode *cur = root_element->xmlChildrenNode;
 
    // if settings field is not found, *settings will be returned 0.
 
    *settings = 0;
 
    while (cur!=NULL) {
 
      if ((!xmlStrcmp(cur->name, (const xmlChar *)"settings"))){
 
	*settings = xmlCopyNode(cur,1);
 
      }
 
      cur=cur->next;
 
    }
 
  }
 
  xmlFreeDoc(doc);
 

	
 
  /*
 
   *Free the global variables that may
 
   *have been allocated by the parser.
 
   */
 
  xmlCleanupParser();
 

	
 
  // We're doing this so we can manually delete walls with by adding the 'delete="true"' property
 
  CleanUpCellNodeLists();
 
}
 

	
 

	
 
void Parameter::XMLRead(xmlNode *root) {
 
	
 
	xmlNode *cur = root->xmlChildrenNode;
 
	while (cur!=NULL) {
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"parameter"))){
 
			xmlNode *par_node = cur->xmlChildrenNode;
 
			while (par_node!=NULL) {
 
				{
 
					if (!xmlStrcmp(par_node->name, (const xmlChar *)"par")) {
 
						xmlChar *namec = xmlGetProp(par_node, BAD_CAST "name");
 
						xmlChar *valc = xmlGetProp(par_node, BAD_CAST "val");
 
						if (valc) {
 
							AssignValToPar((const char*)namec,(const char*)valc);
 
						} else {
 
							/* Probably a valarray */
 
							xmlNode *sub_par_node = par_node->xmlChildrenNode;
 
							vector<double> valarray; 
 
							while (sub_par_node != NULL) {
 
								if (!xmlStrcmp(sub_par_node->name, (const xmlChar *)"valarray")) {
 
									valarray = XMLIO::XMLReadValArray(sub_par_node);
 
								}
 
								sub_par_node = sub_par_node->next;
 
							}
 
							AssignValArrayToPar((const char*)namec, valarray);
 
						}
 
					}
 
				}	  
 
				par_node = par_node->next;
 
			}
 
			
 
void Parameter::XMLRead(xmlNode *root)
 
{
 

	
 
  xmlNode *cur = root->xmlChildrenNode;
 
  while (cur!=NULL) {
 
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"parameter"))){
 
      xmlNode *par_node = cur->xmlChildrenNode;
 
      while (par_node!=NULL) {
 
	{
 
	  if (!xmlStrcmp(par_node->name, (const xmlChar *)"par")) {
 
	    xmlChar *namec = xmlGetProp(par_node, BAD_CAST "name");
 
	    xmlChar *valc = xmlGetProp(par_node, BAD_CAST "val");
 
	    if (valc) {
 
	      AssignValToPar((const char*)namec,(const char*)valc);
 
	    } else {
 
	      /* Probably a valarray */
 
	      xmlNode *sub_par_node = par_node->xmlChildrenNode;
 
	      vector<double> valarray; 
 
	      while (sub_par_node != NULL) {
 
		if (!xmlStrcmp(sub_par_node->name, (const xmlChar *)"valarray")) {
 
		  valarray = XMLIO::XMLReadValArray(sub_par_node);
 
		}
 
		cur=cur->next;
 
	}
 
    
 
		sub_par_node = sub_par_node->next;
 
	      }
 
	      AssignValArrayToPar((const char*)namec, valarray);
 
	    }
 
	  }
 
	}	  
 
	par_node = par_node->next;
 
      }
 
    }
 
    cur=cur->next;
 
  }
 
}
 

	
 
/* finis */
src/xmlwrite.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _XML_WRITE_H_
 
#define _XML_WRITE_H_
 

	
 
#include <vector>
 
#include <libxml/tree.h>
 
#include <cstring>
 

	
 
namespace XMLIO {
 

	
 
	std::vector <double> XMLReadValArray(xmlNode *cur);
 
  std::vector <double> XMLReadValArray(xmlNode *cur);
 
  template<class For, class E> long list_index (For beg, For end, E *elem) {
 
    
 

	
 
    long n = 0;
 
    for (For i=beg;
 
	 i!=end;
 
	 i++) {
 
      if (*i == elem) {
 
	return n;
 
      }
 
      n++;
 
    }
 
    return -1;
 
  }
 
 	
 
}
 

	
 

	
 
static const char * bool_names[2] = {"true","false"};
 

	
 
inline const char *bool_name(bool q) { return q ? bool_names[0] : bool_names[1]; }
 

	
 
inline bool strtobool(const char *str) { 
 
  if (!strcmp(str, "true")) {
 
    return true;
 
  } else {
 
    if (!strcmp(str, "false")) {
 
      return false;
 
    } else {
 
      throw("Error in xmlwrite.cpp : strtobool(const char *str). Parameter passed other than \"true\" or \"false\".");
 
    }
 
  }
 
}
 

	
 
#endif
 

	
 
/* finis */
0 comments (0 inline, 0 general)