MOOSE - Multiscale Object Oriented Simulation Environment
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
CylBase.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 ** This program is part of 'MOOSE', the
3 ** Messaging Object Oriented Simulation Environment.
4 ** Copyright (C) 2011 Upinder S. Bhalla. and NCBS
5 ** It is made available under the terms of the
6 ** GNU Lesser General Public License version 2.1
7 ** See the file COPYING.LIB for the full notice.
8 **********************************************************************/
9 //#include <vector>
10 //#include <cassert>
11 //using namespace std;
12 #include "header.h"
13 #include "SparseMatrix.h"
14 // #include "ElementValueFinfo.h"
15 #include "Boundary.h"
16 #include "MeshEntry.h"
17 #include "VoxelJunction.h"
18 #include "ChemCompt.h"
19 #include "MeshCompt.h"
20 #include "CubeMesh.h"
21 #include "CylBase.h"
22 #include "../utility/Vec.h"
23 
24 extern const double PI; // defined in consts.cpp
25 
26 CylBase::CylBase( double x, double y, double z,
27  double dia, double length, unsigned int numDivs )
28  :
29  x_( x ),
30  y_( y ),
31  z_( z ),
32  dia_( dia ),
33  length_( length ),
34  numDivs_( numDivs ),
35  isCylinder_( false )
36 {
37  ;
38 }
39 
41  :
42  x_( 0.0 ),
43  y_( 0.0 ),
44  z_( 0.0 ),
45  dia_( 1.0 ),
46  length_( 1.0 ),
47  numDivs_( 1.0 ),
48  isCylinder_( false )
49 {
50  ;
51 }
52 
53 void CylBase::setX( double v )
54 {
55  x_ = v;
56 }
57 
58 double CylBase::getX() const
59 {
60  return x_;
61 }
62 
63 void CylBase::setY( double v )
64 {
65  y_ = v;
66 }
67 
68 double CylBase::getY() const
69 {
70  return y_;
71 }
72 
73 void CylBase::setZ( double v )
74 {
75  z_ = v;
76 }
77 
78 double CylBase::getZ() const
79 {
80  return z_;
81 }
82 
83 void CylBase::setDia( double v )
84 {
85  dia_ = v;
86 }
87 
88 double CylBase::getDia() const
89 {
90  return dia_;
91 }
92 
93 void CylBase::setLength( double v )
94 {
95  length_ = v;
96 }
97 
98 double CylBase::getLength() const
99 {
100  return length_;
101 }
102 
103 void CylBase::setNumDivs( unsigned int v )
104 {
105  numDivs_ = v;
106 }
107 
108 unsigned int CylBase::getNumDivs() const
109 {
110  return numDivs_;
111 }
112 
114 {
115  isCylinder_ = v;
116 }
117 
119 {
120  return isCylinder_;
121 }
123 // FieldElement assignment stuff for MeshEntries
125 
135 double CylBase::volume( const CylBase& parent ) const
136 {
137  if ( isCylinder_ )
138  return length_ * dia_ * dia_ * PI / 4.0;
139  double r0 = parent.dia_/2.0;
140  double r1 = dia_/2.0;
141  return length_ * ( r0*r0 + r0 *r1 + r1 * r1 ) * PI / 3.0;
142 }
143 
152 double CylBase::voxelVolume( const CylBase& parent, unsigned int fid ) const
153 {
154  assert( numDivs_ > fid );
155  if ( isCylinder_ )
156  return length_ * dia_ * dia_ * PI / ( 4.0 * numDivs_ );
157 
158  double frac0 = ( static_cast< double >( fid ) ) /
159  static_cast< double >( numDivs_ );
160  double frac1 = ( static_cast< double >( fid + 1 ) ) /
161  static_cast< double >( numDivs_ );
162  double r0 = 0.5 * ( parent.dia_ * ( 1.0 - frac0 ) + dia_ * frac0 );
163  double r1 = 0.5 * ( parent.dia_ * ( 1.0 - frac1 ) + dia_ * frac1 );
164  double s0 = length_ * frac0;
165  double s1 = length_ * frac1;
166 
167  return (s1 - s0) * ( r0*r0 + r0 *r1 + r1 * r1 ) * PI / 3.0;
168 }
169 
172 vector< double > CylBase::getCoordinates(
173  const CylBase& parent, unsigned int fid ) const
174 {
175  assert( numDivs_ > fid );
176  double frac0 = ( static_cast< double >( fid ) ) /
177  static_cast< double >( numDivs_ );
178  double frac1 = ( static_cast< double >( fid + 1 ) ) /
179  static_cast< double >( numDivs_ );
180 
181  double r0 = 0.5 * ( parent.dia_ * ( 1.0 - frac0 ) + dia_ * frac0 );
182  // equivalent: double r0 = parent.dia_ + frac0 * ( dia_ - parent.dia_ );
183  double r1 = 0.5 * ( parent.dia_ * ( 1.0 - frac1 ) + dia_ * frac1 );
184 
185  vector< double > ret( 10, 0.0 );
186  ret[0] = parent.x_ + frac0 * ( x_ - parent.x_ );
187  ret[1] = parent.y_ + frac0 * ( y_ - parent.y_ );
188  ret[2] = parent.z_ + frac0 * ( z_ - parent.z_ );
189  ret[3] = parent.x_ + frac1 * ( x_ - parent.x_ );
190  ret[4] = parent.y_ + frac1 * ( y_ - parent.y_ );
191  ret[5] = parent.z_ + frac1 * ( z_ - parent.z_ );
192  ret[6] = r0;
193  ret[7] = r1;
194  ret[8] = 0;
195  ret[9] = 0;
196 
197  return ret;
198 }
199 
211  const CylBase& parent, unsigned int fid ) const
212 {
213  assert( fid < numDivs_ + 1 );
214  if ( isCylinder_ )
215  return PI * dia_ * dia_ / 4.0;
216  double frac0 = ( static_cast< double >( fid ) ) /
217  static_cast< double >( numDivs_ );
218  double r0 = 0.5 * ( parent.dia_ * ( 1.0 - frac0 ) + dia_ * frac0 );
219  return PI * r0 * r0;
220 }
221 
224  const CylBase& parent, unsigned int fid ) const
225 {
226  assert( fid < numDivs_ );
227  if ( isCylinder_ )
228  return PI * dia_ * dia_ / 4.0;
229  double frac0 = ( 0.5 + static_cast< double >( fid ) ) /
230  static_cast< double >( numDivs_ );
231  double r0 = 0.5 * ( parent.dia_ * ( 1.0 - frac0 ) + dia_ * frac0 );
232  return PI * r0 * r0;
233 }
234 
236 {
237  return length_ / numDivs_;
238 }
239 
240 
241 // Select grid size. Ideally the meshes should be comparable.
242 double CylBase::selectGridSize( double h, double dia1,
243  double granularity ) const
244 {
245  if ( length_ < 1e-7 && numDivs_ == 1 ) { // It is a disc, not a cylinder
246  return granularity * dia_ / 2.0;
247  }
248 
249  double lambda = length_ / numDivs_;
250  if ( h > lambda )
251  h = lambda;
252  if ( h > dia_ / 2.0 )
253  h = dia_ / 2.0;
254  if ( h > dia1/2.0 )
255  h = dia1/2.0;
256  h *= granularity;
257  unsigned int num = ceil( lambda / h );
258  h = lambda / num;
259 
260  return h;
261 }
262 
263 static void fillPointsOnCircle(
264  const Vec& u, const Vec& v, const Vec& q,
265  double h, double r, vector< double >& area,
266  const CubeMesh* other
267  )
268 {
269  // fine-tune the h spacing so it is integral around circle.
270  // This will cause small errors in area estimate but they will
271  // be anisotropic. The alternative will have large errors toward
272  // 360 degrees, but not elsewhere.
273  unsigned int numAngle = floor( 2.0 * PI * r / h + 0.5 );
274  assert( numAngle > 0 );
275  double dtheta = 2.0 * PI / numAngle;
276  double dArea = h * dtheta * r;
277  // March along points on surface of circle centred at q.
278  for ( unsigned int j = 0; j < numAngle; ++j ) {
279  double theta = j * dtheta;
280  double c = cos( theta );
281  double s = sin( theta );
282  double p0 = q.a0() + r * ( u.a0() * c + v.a0() * s );
283  double p1 = q.a1() + r * ( u.a1() * c + v.a1() * s );
284  double p2 = q.a2() + r * ( u.a2() * c + v.a2() * s );
285  unsigned int index = other->spaceToIndex( p0, p1, p2 );
286  if ( index != CubeMesh::EMPTY )
287  area[index] += dArea;
288  }
289 }
290 
291 static void fillPointsOnDisc(
292  const Vec& u, const Vec& v, const Vec& q,
293  double h, double r, vector< double >& area,
294  const CubeMesh* other
295  )
296 {
297  unsigned int numRadial = floor( r / h + 0.5 );
298  double dRadial = r / numRadial;
299  for ( unsigned int i = 0; i < numRadial; ++i ) {
300  double a = ( i + 0.5 ) * dRadial;
301  unsigned int numAngle = floor( 2.0 * PI * a / h + 0.5 );
302  if ( i == 0 )
303  numAngle = 1;
304  double dtheta = 2.0 * PI / numAngle;
305  double dArea = dRadial * dtheta * a;
306  for ( unsigned int j = 0; j < numAngle; ++j ) {
307  double theta = j * dtheta;
308  double c = cos( theta );
309  double s = sin( theta );
310  double p0 = q.a0() + a * ( u.a0() * c + v.a0() * s );
311  double p1 = q.a1() + a * ( u.a1() * c + v.a1() * s );
312  double p2 = q.a2() + a * ( u.a2() * c + v.a2() * s );
313  unsigned int index = other->spaceToIndex( p0, p1, p2 );
314  if ( index != CubeMesh::EMPTY )
315  area[index] += dArea;
316  }
317  }
318 }
319 
321  const CylBase& parent,
322  unsigned int startIndex,
323  double granularity,
324  vector< VoxelJunction >& ret,
325  bool useCylinderCurve, bool useCylinderCap ) const
326 {
327  const CubeMesh* other = dynamic_cast< const CubeMesh* >( compt );
328  assert( other );
329  const double EPSILON = 1e-18;
330  Vec a( parent.x_ - x_, parent.y_ - y_, parent.z_ - z_ );
331  Vec u;
332  Vec v;
333  a.orthogonalAxes( u, v );
334 
335  double h = selectGridSize( other->getDx(), parent.dia_/2, granularity );
336  double lambda = length_ / numDivs_;
337 
338  unsigned int num = floor( 0.1 + lambda / h );
339  // March along axis of cylinder.
340  // q is the location of the point along axis.
341  double rSlope = ( dia_ - parent.dia_ ) * 0.5 / length_;
342  for ( unsigned int i = 0; i < numDivs_; ++i ) {
343  vector< double >area( other->getNumEntries(), 0.0 );
344  if ( useCylinderCurve ) {
345  for ( unsigned int j = 0; j < num; ++j ) {
346  unsigned int m = i * num + j;
347  double frac = ( m * h + h/2.0 ) / length_;
348  double q0 = x_ + a.a0() * frac;
349  double q1 = y_ + a.a1() * frac;
350  double q2 = z_ + a.a2() * frac;
351  // get radius of cylinder at this point.
352  double r = dia_/2.0;
353  if ( !isCylinder_ ) // Use the more complicated conic value
354  r = parent.dia_/2.0 + frac * rSlope;
355  fillPointsOnCircle( u, v, Vec( q0, q1, q2 ),
356  h, r, area, other );
357  }
358  }
359  if ( useCylinderCap && i == numDivs_ - 1 ) {
360  fillPointsOnDisc( u, v, Vec( x_, y_, z_ ),
361  h, dia_/2.0, area, other );
362  }
363  // Go through all cubeMesh entries and compute diffusion
364  // cross-section. Assume this is through a membrane, so the
365  // only factor relevant is area. Not the distance.
366  for ( unsigned int k = 0; k < area.size(); ++k ) {
367  if ( area[k] > EPSILON ) {
368  ret.push_back( VoxelJunction( i + startIndex, k, area[k] ));
369  }
370  }
371  }
372 }
373 
374 // this is the function that does the actual calculation.
375 // Returns radial distance from self to axis formed from parent to self.
376 // also sends back linePos, the fraction along the line, and r, the
377 // radius of the parent tapering cylinder at the point of linePos.
378 double CylBase::nearest( double x, double y, double z,
379  const CylBase& parent,
380  double& linePos, double& r ) const
381 {
382  const double EPSILON = 1e-8; // 10 nm is too small for any compt.
383  // Consider a = parent and b = self, and c = x,y,z.
384  // Fraction along cylinder axis ab = k
385  // k = (c - a).(b - a)/((b-a).(b-a))
386  //
387  // Then, point p along line from parent to self is
388  // p = k( self-parent) + parent.
389  //
390  // So distance from c to p is what we want.
391  //
392  // If k is
393  //
394  Vec a( parent.x_, parent.y_, parent.z_ );
395  Vec b( x_, y_, z_ );
396  Vec c( x, y, z );
397 
398  double dist = b.distance( a );
399  assert( dist > EPSILON );
400  double k = ( b - a ).dotProduct( c - a );
401  k /= dist * dist;
402  Vec pt = a.pointOnLine( b, k );
403 
404  double ret = c.distance(pt);
405  linePos = k;
406  // For now I disable the positioning with a tapering cylinder.
407  // double rSlope = 0.5 * ( dia_ - parent.dia_ ) / numDivs_;
408  double rSlope = 0;
409  r = dia_/2.0 + k * numDivs_ * rSlope;
410  return ret;
411 }
412 
413 // This function returns the index.
414 double CylBase::nearest( double x, double y, double z,
415  const CylBase& parent,
416  unsigned int& index ) const
417 {
418  double k = 0.0;
419  double r;
420  double ret = nearest( x, y, z, parent, k, r );
421  if ( k < 0.0 ) {
422  ret = -ret;
423  index = 0;
424  } else if ( k > 1.0 ) {
425  ret = -ret;
426  index = numDivs_ - 1;
427  } else { // Inside length of cylinder, now is it inside radius?
428  index = k * numDivs_;
429  if ( index >= numDivs_ )
430  index = numDivs_ - 1;
431  // double ri = r0_ + (index + 0.5) * rSlope_;
432  if ( ret > r * 1.01 ) // Handle roundoff
433  ret = -ret;
434  }
435  return ret;
436 }
437 
double x_
end of the node. The start is given by parent coords.
Definition: CylBase.h:103
static void fillPointsOnDisc(const Vec &u, const Vec &v, const Vec &q, double h, double r, vector< double > &area, const CubeMesh *other)
Definition: CylBase.cpp:291
static void fillPointsOnCircle(const Vec &u, const Vec &v, const Vec &q, double h, double r, vector< double > &area, const CubeMesh *other)
Definition: CylBase.cpp:263
const double PI
Definition: consts.cpp:12
double getLength() const
Definition: CylBase.cpp:98
double a0() const
Definition: Vec.h:34
void setNumDivs(unsigned int v)
Definition: CylBase.cpp:103
double length_
Diameter of node end.
Definition: CylBase.h:108
void setX(double v)
Definition: CylBase.cpp:53
unsigned int spaceToIndex(double x, double y, double z) const
Converts the 3-D coords to an index. EMPTY if out of range.
Definition: CubeMesh.cpp:1171
double getX() const
Definition: CylBase.cpp:58
double dia_
Definition: CylBase.h:107
double voxelVolume(const CylBase &parent, unsigned int fid) const
Definition: CylBase.cpp:152
double getDx() const
Definition: CubeMesh.cpp:507
bool isCylinder_
Number of subdivisions of cylinder.
Definition: CylBase.h:110
double a2() const
Definition: Vec.h:40
CylBase()
Definition: CylBase.cpp:40
double getDiffusionArea(const CylBase &parent, unsigned int index) const
Definition: CylBase.cpp:210
double volume(const CylBase &parent) const
Returns vol of current node. Usually needs to refer to parent.
Definition: CylBase.cpp:135
void setLength(double v)
Definition: CylBase.cpp:93
double getY() const
Definition: CylBase.cpp:68
vector< double > getCoordinates(const CylBase &parent, unsigned int entry) const
Definition: CylBase.cpp:172
double nearest(double x, double y, double z, const CylBase &parent, double &linePos, double &r) const
Definition: CylBase.cpp:378
unsigned int getNumEntries() const
Definition: ChemCompt.cpp:390
unsigned int numDivs_
Length of compartment.
Definition: CylBase.h:109
Definition: Vec.h:13
static SrcFinfo0 s0("s0","")
void matchCubeMeshEntries(const ChemCompt *other, const CylBase &parent, unsigned int startIndex, double granularity, vector< VoxelJunction > &ret, bool useCylinderCurve, bool useCylinderCap) const
Definition: CylBase.cpp:320
void setZ(double v)
Definition: CylBase.cpp:73
double getMiddleArea(const CylBase &parent, unsigned int index) const
Return cross-section area of middle of specified voxel.
Definition: CylBase.cpp:223
double distance(const Vec &other) const
Definition: Vec.cpp:81
bool getIsCylinder() const
Definition: CylBase.cpp:118
double z_
Definition: CylBase.h:105
void setIsCylinder(bool v)
Definition: CylBase.cpp:113
void setY(double v)
Definition: CylBase.cpp:63
double getDia() const
Definition: CylBase.cpp:88
double getZ() const
Definition: CylBase.cpp:78
void setDia(double v)
Definition: CylBase.cpp:83
static const unsigned int EMPTY
Definition: CubeMesh.h:285
double y_
Definition: CylBase.h:104
void orthogonalAxes(Vec &u, Vec &v) const
Generates vectors u and v to form a mutually orthogonal system.
Definition: Vec.cpp:41
double a1() const
Definition: Vec.h:37
unsigned int getNumDivs() const
Definition: CylBase.cpp:108
#define EPSILON
Definition: MatrixOps.h:28
double selectGridSize(double h, double dia1, double granularity) const
Definition: CylBase.cpp:242
double getVoxelLength() const
Return length of voxel. All are equal.
Definition: CylBase.cpp:235
Vec pointOnLine(const Vec &end, double k)
Definition: Vec.cpp:53