diff --git a/data/leaves/bend.xml b/data/leaves/bend.xml new file mode 100644 --- /dev/null +++ b/data/leaves/bend.xml @@ -0,0 +1,1061 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #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) {} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +