#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(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(); } } } // 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) {}