#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 "testplugin.h"
/* #define _xstr_(s) _str_(s)
#define _str_(s) #s
#include _xstr_(REACTIONS_HEADER)
*/
extern Parameter par;
MainBase *main_window = 0;
double auxin_account = 0.;
TestPlugin *plugin = new TestPlugin();
#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) {
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 << ".pdf";
if (par.storage_stride <= par.xml_storage_stride) {
frame++;
}
// Write high-res JPG snapshot every plot step
Save(fname.str().c_str(), "PDF");
*/
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());
}
}
}
void Cell::Flux(double *flux, double *D) {
// loop over cell edges
for (int c=0;c<Cell::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<Cell::nchem;c++) {
double phi = (*i)->length * ( D[c] ) * ( (*i)->c2->chem[c] - chem[c] );
if ((*i)->c1!=this) {
cerr << "Warning, bad cells boundary: " << (*i)->c1->index << ", " << index << endl;
}
flux[c] += phi;
}
}
}
INIT {
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 {
Cell &circle=mesh.CircularCell(0,0,10,10);
circle.SetTargetArea(circle.CalcArea());
mesh.SetBaseArea();
// clean up chemicals
for (int c=0; c<Cell::NChem(); c++) {
circle.SetChemical(c, 0.);
}
}
}
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.LoopCurrentCells(&TestPlugin::CellHouseKeeping); // this includes cell division
// Reaction diffusion
/*CelltoCellTransport *transport_f = &TestPlugin::CelltoCellTransport;
CellReaction *cellreaction_f = new plugin->CellDynamics();
WallReaction *wall_f = new WallDynamics();*/
mesh.ReactDiffuse(plugin, par.rd_dt);
t++;
Plot(par.resize_stride);
/*QVector< QPair<double, int> > angles=mesh.VertexAnglesValues();
QString afname=QString("Angles/anglesvalues%1.dat").arg(t,6,10,QChar('0'));
ofstream af(afname.toStdString().c_str());
*/
/*for (QVector< QPair<qreal, int> >::const_iterator v=angles.begin();
v!=angles.end();
v++) {
af << v->first << " " << v->second << endl;
}
*/
}
} else {
/* TransportFunction *transport_f = new CelltoCellTransport();
CellReaction *cellreaction_f = new CellDynamics();
WallReaction *wall_f = new WallDynamics();
mesh.ReactDiffuse_New(transport_f, cellreaction_f, wall_f, par.rd_dt);*/
mesh.ReactDiffuse(plugin, par.rd_dt);
Plot(par.resize_stride);
}
i++;
return mesh.getTime();
}
/* Called if a cell is clicked */
void Cell::OnClick(QMouseEvent *e) {
}
void Wall::OnWallInsert(void) {
}
int main(int argc,char **argv) {
try {
int c;
char *leaffile=0;
while (1) {
//int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] = {
{"batch", 0, 0, 0},
{"leaffile", 2, 0, 0}
};
// short option 'p' creates trouble for non-commandline usage on MacOSX. Option -p changed to -P (capital)
static char *short_options = "bl";
c = getopt_long (argc, argv, "bl:",
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 '?':
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");
}
MakeDir("Angles");
bool useGUI = !batch;
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()) );
}
main_window->Init(leaffile);
Cell::SetMagnification(10);
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();
}
}
}
// Executed after the cellular mechanics steps have equillibrized
class CellHouseKeeping {
public:
void operator() (Cell &c) const {
c.EnlargeTargetArea(par.cell_expansion_rate);
if (c.Area() > par.rel_cell_div_threshold * c.BaseArea() ) {
c.Divide();
}
}
};
// The number of chemical species in the cels
const int Cell::nchem = 0;
// Differential equations describing transport of chemicals from cell to cell
class CelltoCellTransport : public TransportFunction {
public:
virtual void operator()(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)
class WallDynamics : public WallReaction {
public:
virtual void operator()(Wall *w, double *dw1, double *dw2) {};
};
// Differential equations describing chemical reactions inside the cells
class CellDynamics : public CellReaction {
public:
virtual void operator()(Cell *c, double *dchem) {
};
};
// Rules for cell coloring
void Cell::SetColor(QColor &color) { }
// To be executed after cell division
void Cell::OnDivide(ParentInfo &parent_info, Cell &daughter) {}
|
|