/*
*
* This file is part of the Virtual Leaf.
*
* VirtualLeaf 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.
*
* VirtualLeaf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Virtual Leaf. If not, see .
*
* Copyright 2010 Roeland Merks.
*
*/
#include
#include
#include
#include
#include
#include
#ifdef QTGRAPHICS
#include
#include
#include
#include
#include
//Added by qt3to4:
#include
#include
#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()
{
chem=new double[NChem()];
for (int i=0;i=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::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::const_iterator i = nodes.begin(); i!=nodes.end(); i++) {
os << (*i)->Index() << "( " << *i << ") ";
}
os << " } ";
for (list::const_iterator i = walls.begin(); i!=walls.end(); i++) {
(*i)->print(os);
os << ", ";
}
os << endl;
os << " [ area = " << area << " ]";
os << " [ walls = ";
for (list::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;
}
double CellBase::CalcArea(void) const
{
double loc_area=0.;
for (list::const_iterator i=nodes.begin(); i!=(nodes.end()); i++) {
list::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::const_iterator i=nodes.begin(); i!=(nodes.end()); i++) {
list::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::const_iterator nb;
list::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);
}
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::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::const_iterator nb;
list::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)
{
neighbors.clear();
for (//list::const_reverse_iterator wit=walls.rbegin();
list::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());
}
}
// remove all boundary_polygons from the list
list ::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::const_iterator i=nodes.begin();i!=nodes.end();i++) {
os << *i << " ";
}
os << endl;
os << index << " " << neighbors.size() << endl;
for (list::const_iterator i=neighbors.begin();i!=neighbors.end();i++) {
os << *i << " ";
}
os << endl << walls.size() << endl << endl;
os << NChem() << " ";
for (int i=0;i::const_iterator i=nodes.begin(); i!=nodes.end(); i++) {
(*i)->Unfix();
}
}
void CellBase::FixNodes(void)
{
for (list::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::const_iterator i = nodes.begin(); i!=nodes.end(); i++) {
info_string += QString("%1 ").arg((*i)->Index());
}
info_string += " } ";
return info_string;
}
/* finis*/