MOOSE - Multiscale Object Oriented Simulation Environment
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
CylMesh.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 
10 #include "header.h"
11 #include "SparseMatrix.h"
12 #include "ElementValueFinfo.h"
13 #include "../utility/Vec.h"
14 #include "Boundary.h"
15 #include "MeshEntry.h"
16 // #include "Stencil.h"
17 #include "ChemCompt.h"
18 #include "MeshCompt.h"
19 #include "CubeMesh.h"
20 #include "CylBase.h"
21 #include "NeuroNode.h"
22 // #include "NeuroStencil.h"
23 #include "NeuroMesh.h"
24 #include "CylMesh.h"
25 #include "EndoMesh.h"
26 #include "../utility/numutil.h"
28 {
30  // Field Definitions
33  "x0",
34  "x coord of one end",
37  );
39  "y0",
40  "y coord of one end",
43  );
45  "z0",
46  "z coord of one end",
49  );
51  "r0",
52  "Radius of one end",
55  );
57  "x1",
58  "x coord of other end",
61  );
63  "y1",
64  "y coord of other end",
67  );
69  "z1",
70  "z coord of other end",
73  );
75  "r1",
76  "Radius of other end",
79  );
81  "coords",
82  "All the coords as a single vector: x0 y0 z0 x1 y1 z1 r0 r1 diffLength",
85  );
86 
87  static ElementValueFinfo< CylMesh, double > diffLength(
88  "diffLength",
89  "Length constant to use for subdivisions"
90  "The system will attempt to subdivide using compartments of"
91  "length diffLength on average. If the cylinder has different end"
92  "diameters r0 and r1, it will scale to smaller lengths"
93  "for the smaller diameter end and vice versa."
94  "Once the value is set it will recompute diffLength as "
95  "totLength/numEntries",
98  );
99 
100  static ReadOnlyValueFinfo< CylMesh, unsigned int > numDiffCompts(
101  "numDiffCompts",
102  "Number of diffusive compartments in model",
104  );
105 
106  static ReadOnlyValueFinfo< CylMesh, double > totLength(
107  "totLength",
108  "Total length of cylinder",
110  );
111 
113  // MsgDest Definitions
115 
117  // Field Elements
119 
120  static Finfo* cylMeshFinfos[] = {
121  &x0, // Value
122  &y0, // Value
123  &z0, // Value
124  &r0, // Value
125  &x1, // Value
126  &y1, // Value
127  &z1, // Value
128  &r1, // Value
129  &diffLength, // Value
130  &coords, // Value
131  &numDiffCompts, // ReadOnlyValue
132  &totLength, // ReadOnlyValue
133  };
134 
135  static string doc[] =
136  {
137  "Name", "CylMesh",
138  "Author", "Upi Bhalla",
139  "Description", "Chemical compartment with cylindrical geometry. "
140  "Defaults to a uniform cylinder of radius 1 micron, "
141  "length 100 microns, and voxel length 1 micron so there "
142  "are 100 voxels in the cylinder. "
143  "The cylinder can be given a linear taper, by assigning "
144  "different radii r0 and r1 to the two ends. ",
145  };
146  static Dinfo< CylMesh > dinfo;
147  static Cinfo cylMeshCinfo (
148  "CylMesh",
150  cylMeshFinfos,
151  sizeof( cylMeshFinfos ) / sizeof ( Finfo* ),
152  &dinfo,
153  doc,
154  sizeof(doc)/sizeof(string)
155  );
156 
157  return &cylMeshCinfo;
158 }
159 
161 // Basic class Definitions
163 
165 
167 // Class stuff.
170  :
171  numEntries_( 100 ),
172  useCaps_( 0 ),
173  isToroid_( false ),
174  x0_( 0.0 ),
175  y0_( 0.0 ),
176  z0_( 0.0 ),
177  x1_( 100.0e-6 ),
178  y1_( 0.0 ),
179  z1_( 0.0 ),
180  r0_( 1.0e-6 ),
181  r1_( 1.0e-6 ),
182  diffLength_( 1.0e-6 ),
183  surfaceGranularity_( 0.1 ),
184  totLen_( 100.0e-6 ),
185  rSlope_( 0.0 ),
186  lenSlope_( 0.0 )
187 {
188  ;
189 }
190 
192 {
193  ;
194 }
195 
197 // Field assignment stuff
199 
205 void CylMesh::updateCoords( const Eref& e, const vector< double >& concs )
206 {
207  double temp = sqrt(
208  ( x1_ - x0_ ) * ( x1_ - x0_ ) +
209  ( y1_ - y0_ ) * ( y1_ - y0_ ) +
210  ( z1_ - z0_ ) * ( z1_ - z0_ )
211  );
212 
213  if ( doubleEq( temp, 0.0 ) ) {
214  cout << "Error: CylMesh::updateCoords:\n"
215  "total length of compartment = 0 with these parameters\n";
216  return;
217  }
218  totLen_ = temp;
219 
220 
221  temp = totLen_ / diffLength_;
222  if ( temp < 1.0 ) {
224  numEntries_ = 1;
225  } else {
226  numEntries_ = static_cast< unsigned int >( round ( temp ) );
228  }
229  rSlope_ = ( r1_ - r0_ ) / numEntries_;
230  lenSlope_ = diffLength_ * rSlope_ * 2 / ( r0_ + r1_ );
231 
232  // dx2_[0] = diffLength_;
233  // dx2_[1] = diffLength_;
234  buildStencil();
235  setChildConcs( e, concs, 0 );
236 }
237 
238 void CylMesh::setX0( const Eref& e, double v )
239 {
240  vector< double > childConcs;
241  getChildConcs( e, childConcs );
242  x0_ = v;
243  updateCoords( e, childConcs );
244 }
245 
246 double CylMesh::getX0( const Eref& e ) const
247 {
248  return x0_;
249 }
250 
251 void CylMesh::setY0( const Eref& e, double v )
252 {
253  vector< double > childConcs;
254  getChildConcs( e, childConcs );
255  y0_ = v;
256  updateCoords( e, childConcs );
257 }
258 
259 double CylMesh::getY0( const Eref& e ) const
260 {
261  return y0_;
262 }
263 
264 void CylMesh::setZ0( const Eref& e, double v )
265 {
266  vector< double > childConcs;
267  getChildConcs( e, childConcs );
268  z0_ = v;
269  updateCoords( e, childConcs );
270 }
271 
272 double CylMesh::getZ0( const Eref& e ) const
273 {
274  return z0_;
275 }
276 
277 void CylMesh::setR0( const Eref& e, double v )
278 {
279  vector< double > childConcs;
280  getChildConcs( e, childConcs );
281  r0_ = v;
282  updateCoords( e, childConcs );
283 }
284 
285 double CylMesh::getR0( const Eref& e ) const
286 {
287  return r0_;
288 }
289 
290 
291 void CylMesh::setX1( const Eref& e, double v )
292 {
293  vector< double > childConcs;
294  getChildConcs( e, childConcs );
295  x1_ = v;
296  updateCoords( e, childConcs );
297 }
298 
299 double CylMesh::getX1( const Eref& e ) const
300 {
301  return x1_;
302 }
303 
304 void CylMesh::setY1( const Eref& e, double v )
305 {
306  vector< double > childConcs;
307  getChildConcs( e, childConcs );
308  y1_ = v;
309  updateCoords( e, childConcs );
310 }
311 
312 double CylMesh::getY1( const Eref& e ) const
313 {
314  return y1_;
315 }
316 
317 void CylMesh::setZ1( const Eref& e, double v )
318 {
319  vector< double > childConcs;
320  getChildConcs( e, childConcs );
321  z1_ = v;
322  updateCoords( e, childConcs );
323 }
324 
325 double CylMesh::getZ1( const Eref& e ) const
326 {
327  return z1_;
328 }
329 
330 void CylMesh::setR1( const Eref& e, double v )
331 {
332  vector< double > childConcs;
333  getChildConcs( e, childConcs );
334  r1_ = v;
335  updateCoords( e, childConcs );
336 }
337 
338 double CylMesh::getR1( const Eref& e ) const
339 {
340  return r1_;
341 }
342 
343 void CylMesh::innerSetCoords( const Eref& e, const vector< double >& v )
344 {
345  vector< double > childConcs;
346  getChildConcs( e, childConcs );
347  x0_ = v[0];
348  y0_ = v[1];
349  z0_ = v[2];
350 
351  x1_ = v[3];
352  y1_ = v[4];
353  z1_ = v[5];
354 
355  r0_ = v[6];
356  r1_ = v[7];
357 
358  diffLength_ = v[8];
359 
360  updateCoords( e, childConcs );
361 }
362 
363 void CylMesh::setCoords( const Eref& e, vector< double > v )
364 {
365  if ( v.size() < 9 ) {
366  cout << "CylMesh::setCoords: Warning: size of argument vec should be >= 9, was " << v.size() << endl;
367  }
368  innerSetCoords( e, v );
369  transmitChange( e );
370 }
371 
372 vector< double > CylMesh::getCoords( const Eref& e ) const
373 {
374  vector< double > ret( 9 );
375 
376  ret[0] = x0_;
377  ret[1] = y0_;
378  ret[2] = z0_;
379 
380  ret[3] = x1_;
381  ret[4] = y1_;
382  ret[5] = z1_;
383 
384  ret[6] = r0_;
385  ret[7] = r1_;
386 
387  ret[8] = diffLength_;
388  return ret;
389 }
390 
391 
392 void CylMesh::setDiffLength( const Eref& e, double v )
393 {
394  vector< double > childConcs;
395  getChildConcs( e, childConcs );
396  diffLength_ = v;
397  updateCoords( e, childConcs );
398 }
399 
400 double CylMesh::getDiffLength( const Eref& e ) const
401 {
402  return diffLength_;
403 }
404 
405 
406 double CylMesh::getTotLength() const
407 {
408  return totLen_;
409 }
410 
411 unsigned int CylMesh::innerGetDimensions() const
412 {
413  return 3;
414 }
415 
417 // FieldElement assignment stuff for MeshEntries
419 
421 unsigned int CylMesh::getMeshType( unsigned int fid ) const
422 {
423  if ( !isToroid_ && useCaps_ && ( fid == 0 || fid == numEntries_ - 1 ) )
424  return SPHERE_SHELL_SEG;
425 
426  return CYL;
427 }
428 
430 unsigned int CylMesh::getMeshDimensions( unsigned int fid ) const
431 {
432  return 3;
433 }
434 
476 double CylMesh::getMeshEntryVolume( unsigned int fid ) const
478 {
479  double len0 = diffLength_ * 2 * r0_ / ( r0_ + r1_ );
480 
481  double ri = r0_ + (fid + 0.5) * rSlope_;
482  double leni = len0 + ( fid + 0.5 ) * lenSlope_;
483 
484  return leni * ri * ri * PI;
485 }
486 
489 vector< double > CylMesh::getCoordinates( unsigned int fid ) const
490 {
491  vector< double > ret(10, 0.0);
492  double len0 = diffLength_ * 2 * r0_ / ( r0_ + r1_ );
493  // double len0 = diffLength_ * 2 * ( r0_ + rSlope_ / 0.5) / ( r0_ + r1_ );
494  double lenStart = len0 + lenSlope_ * 0.5;
495 
496  double axialStart = fid * lenStart + ( ( fid * (fid - 1 ) )/2 ) * lenSlope_;
497  // fid * totLen_/numEntries_ + (fid - frac ) * lenSlope_;
498  double axialEnd =
499  (fid + 1) * lenStart + ( ( fid * (fid + 1 ) )/2 ) * lenSlope_;
500  // (fid + 1) * totLen_/numEntries_ + (fid - frac + 1.0) * lenSlope_;
501 
502  ret[0] = x0_ + (x1_ - x0_ ) * axialStart/totLen_;
503  ret[1] = y0_ + (y1_ - y0_ ) * axialStart/totLen_;
504  ret[2] = z0_ + (z1_ - z0_ ) * axialStart/totLen_;
505 
506  ret[3] = x0_ + (x1_ - x0_ ) * axialEnd/totLen_;
507  ret[4] = y0_ + (y1_ - y0_ ) * axialEnd/totLen_;
508  ret[5] = z0_ + (z1_ - z0_ ) * axialEnd/totLen_;
509 
510  ret[6] = r0_ + fid * rSlope_;
511  ret[7] = r0_ + (fid + 1.0) * rSlope_;
512 
513  ret[8] = 0;
514  ret[9] = 0;
515 
516  return ret;
517 }
518 
520 vector< double > CylMesh::getDiffusionArea( unsigned int fid ) const
521 {
522  if ( numEntries_ <= 1 )
523  return vector< double >( 0 );
524 
525  double rlow = r0_ + fid * rSlope_;
526  double rhigh = r0_ + (fid + 1.0) * rSlope_;
527 
528  if ( fid == 0 ) {
529  if ( isToroid_ ) {
530  vector < double > ret( 2 );
531  ret[0] = rlow * rlow * PI;
532  ret[1] = rhigh * rhigh * PI;
533  return ret;
534  } else {
535  return vector < double >( 1, rhigh * rhigh * PI );
536  }
537  }
538 
539  if ( fid == (numEntries_ - 1 ) ) {
540  if ( isToroid_ ) {
541  vector < double > ret( 2 );
542  ret[0] = rlow * rlow * PI;
543  ret[1] = r0_ * r0_ * PI; // Wrapping around
544  return ret;
545  } else {
546  return vector < double >( 1, rlow * rlow * PI );
547  }
548  }
549  vector< double > ret( 2 );
550  ret[0] = rlow * rlow * PI;
551  ret[1] = rhigh * rhigh * PI;
552  return ret;
553 }
554 
556 vector< double > CylMesh::getDiffusionScaling( unsigned int fid ) const
557 {
558  if ( numEntries_ <= 1 )
559  return vector< double >( 0 );
560 
561  if ( !isToroid_ && ( fid == 0 || fid == (numEntries_ - 1) ) )
562  return vector< double >( 1, 1.0 );
563 
564  return vector< double >( 2, 1.0 );
565 }
566 
569 double CylMesh::extendedMeshEntryVolume( unsigned int fid ) const
570 {
571  if ( fid < numEntries_ ) {
572  return getMeshEntryVolume( fid );
573  } else {
575  }
576 }
577 
579 // Dest funcsl
581 
584  const SrcFinfo2< unsigned int, vector< double > >* meshStatsFinfo
585  )
586 {
587  vector< double > ret( vGetEntireVolume() / numEntries_ ,1 );
588  meshStatsFinfo->send( e, 1, ret );
589 }
590 
592  const Eref& e,
593  unsigned int numNodes, unsigned int numThreads )
594 {
595  /*
596  unsigned int numEntries = numEntries_;
597  vector< double > vols( numEntries, volume_ / numEntries );
598  vector< unsigned int > localEntries( numEntries );
599  vector< vector< unsigned int > > outgoingEntries;
600  vector< vector< unsigned int > > incomingEntries;
601  */
602  /*
603  double oldvol = getMeshEntryVolume( 0 );
604  meshSplit()->send( e,
605  oldvol,
606  vols, localEntries,
607  outgoingEntries, incomingEntries );
608  */
609 }
611 
615 unsigned int CylMesh::innerGetNumEntries() const
616 {
617  return numEntries_;
618 }
619 
623 void CylMesh::innerSetNumEntries( unsigned int n )
624 {
625  static const unsigned int WayTooLarge = 1000000;
626  if ( n == 0 || n > WayTooLarge ) {
627  cout << "Warning: CylMesh::innerSetNumEntries( " << n <<
628  " ): out of range\n";
629  return;
630  }
631  assert( n > 0 );
632  numEntries_ = n;
633  diffLength_ = totLen_ / n;
634  rSlope_ = ( r1_ - r0_ ) / numEntries_;
635  lenSlope_ = diffLength_ * rSlope_ * 2 / ( r0_ + r1_ );
636 
637  buildStencil();
638 }
639 
640 
642  double volume, unsigned int numEntries )
643 {
647  double r = pow( ( volume / ( PI * 2 ) ), 1.0 / 3 );
648  vector< double > coords( 9, 0 );
649  coords[3] = 2 * r;
650  coords[6] = r;
651  coords[7] = r;
652  coords[8] = 2 * r / numEntries;
653  setCoords( e, coords );
654 }
655 
656 vector< unsigned int > CylMesh::getParentVoxel() const
657 {
658  vector< unsigned int > ret( numEntries_ );
659  if ( numEntries_ > 0 )
660  ret[0] = static_cast< unsigned int >( -1 );
661  for (unsigned int i = 1; i < numEntries_; ++i )
662  ret[i] = i-1;
663 
664  return ret;
665 }
666 
667 const vector< double >& CylMesh::vGetVoxelVolume() const
668 {
669  static vector< double > vol;
670  vol.resize( numEntries_ );
671  for ( unsigned int i = 0; i < numEntries_; ++i )
672  vol[i] = getMeshEntryVolume( i );
673  return vol;
674 }
675 
676 const vector< double >& CylMesh::vGetVoxelMidpoint() const
677 {
678  static vector< double > midpoint( numEntries_ * 3, 0.0 );
679  midpoint.resize( numEntries_ * 3 );
680  double dx = ( x1_ - x0_ ) / numEntries_;
681  double dy = ( y1_ - y0_ ) / numEntries_;
682  double dz = ( z1_ - z0_ ) / numEntries_;
683  vector< double >::iterator j = midpoint.begin();
684  for ( unsigned int i = 0; i < numEntries_; ++i )
685  *j++ = x0_ + dx * i;
686  for ( unsigned int i = 0; i < numEntries_; ++i )
687  *j++ = y0_ + dy * i;
688  for ( unsigned int i = 0; i < numEntries_; ++i )
689  *j++ = z0_ + dz * i;
690 
691  return midpoint;
692 }
693 
694 const vector< double >& CylMesh::getVoxelArea() const
695 {
696  static vector< double > area;
697  area.resize( numEntries_ );
698  for ( unsigned int i = 0; i < numEntries_; ++i ) {
699  double frac = ( 0.5 + static_cast< double >( i ) ) /
700  static_cast< double >( numEntries_ );
701  double r = r0_ * ( 1.0 - frac ) + r1_ * frac;
702  area[i] = r * r * PI;
703  }
704  return area;
705 }
706 
707 const vector< double >& CylMesh::getVoxelLength() const
708 {
709  static vector< double > length;
710  length.assign( numEntries_, totLen_ / numEntries_ );
711  return length;
712 }
713 
715 {
716  double vol = 0.0;
717  for ( unsigned int i = 0; i < numEntries_; ++i )
718  vol += getMeshEntryVolume( i );
719  return vol;
720 }
721 
722 bool CylMesh::vSetVolumeNotRates( double volume )
723 {
724  double oldVol = vGetEntireVolume();
725  double linScale = pow( volume/oldVol, 1.0 / 3.0 );
726  x1_ *= linScale;
727  y1_ *= linScale;
728  z1_ *= linScale;
729  r0_ *= linScale;
730  r1_ *= linScale;
731  totLen_ *= linScale;
732  // Have to scale this so numEntries remains the same.
734  return true;
735 }
736 
738 // Utility function to transmit any changes to target nodes.
740 
742 {
743  /*
744  Id meshEntry( e.id().value() + 1 );
745  assert(
746  meshEntry.eref().data() == reinterpret_cast< char* >( lookupEntry( 0 ) )
747  );
748  double oldvol = getMeshEntryVolume( 0 );
749  unsigned int totalNumEntries = numEntries_;
750  unsigned int localNumEntries = totalNumEntries;
751  unsigned int startEntry = 0;
752  vector< unsigned int > localIndices( localNumEntries ); // empty
753  for ( unsigned int i = 0; i < localNumEntries; ++i )
754  localIndices[i] = i;
755  vector< double > vols( localNumEntries, volume_ / numEntries_ );
756  vector< vector< unsigned int > > outgoingEntries; // [node#][Entry#]
757  vector< vector< unsigned int > > incomingEntries; // [node#][Entry#]
758 
759  // This function updates the size of the FieldDataHandler for the
760  // MeshEntries.
761  DataHandler* dh = meshEntry.element()->dataHandler();
762  FieldDataHandlerBase* fdh = dynamic_cast< FieldDataHandlerBase* >( dh );
763  assert( fdh );
764  if ( totalNumEntries > fdh->getMaxFieldEntries() ) {
765  fdh->setMaxFieldEntries( localNumEntries );
766  }
767 
768  // This message tells the Stoich about the new mesh, and also about
769  // how it communicates with other nodes.
770  meshSplit()->fastSend( e,
771  oldvol,
772  vols, localIndices,
773  outgoingEntries, incomingEntries );
774 
775  // This func goes down to the MeshEntry to tell all the pools and
776  // Reacs to deal with the new mesh. They then update the stoich.
777  lookupEntry( 0 )->triggerRemesh( meshEntry.eref(),
778  oldvol, startEntry, localIndices, vols );
779  */
780 }
781 
783 // Utility function to set up Stencil for diffusion
786 {
788  for ( unsigned int i = 0; i < numEntries_; ++i ) {
789  double rLow = r0_ + i * rSlope_;
790  double rHigh = r0_ + (i + 1.0) * rSlope_;
791  double aLow = rLow * rLow * PI;
792  double aHigh = rHigh * rHigh * PI;
793  vector< double > entry;
794  vector< unsigned int > colIndex;
795  if ( i == 0 ) {
796  colIndex.push_back( 1 );
797  entry.push_back( aHigh / diffLength_ );
798  if ( isToroid_ ) {
799  colIndex.push_back( numEntries_ - 1 );
800  entry.push_back( aLow / diffLength_ );
801  }
802  } else if ( i == numEntries_ - 1 ) {
803  if ( isToroid_ ) {
804  colIndex.push_back( 0 );
805  if ( r0_ < r1_ )
806  entry.push_back( r0_ * r0_ * PI / diffLength_ );
807  else
808  entry.push_back( r1_ * r1_ * PI / diffLength_ );
809  }
810  colIndex.push_back( numEntries_ - 2 );
811  entry.push_back( aLow / diffLength_ );
812  } else { // Mostly it is in the middle.
813  colIndex.push_back( i - 1 );
814  entry.push_back( aLow / diffLength_ );
815  colIndex.push_back( i + 1 );
816  entry.push_back( aHigh / diffLength_ );
817  }
818  addRow( i, entry, colIndex );
819  }
821 }
822 
824 // Utility function for junctions
826 
828  vector< VoxelJunction >& ret ) const
829 {
830  // This is seriously ugly, and what virtual funcs were meant to handle.
831  // Dirty hack for now.
832  const CylMesh* cyl = dynamic_cast< const CylMesh* >( other );
833  if ( cyl ) {
834  matchCylMeshEntries( cyl, ret );
835  return;
836  }
837  const EndoMesh* em = dynamic_cast< const EndoMesh* >( other );
838  if ( em )
839  {
840  em->matchMeshEntries( this, ret );
841  flipRet( ret );
842  return;
843  }
844  const CubeMesh* cube = dynamic_cast< const CubeMesh* >( other );
845  if ( cube ) {
846  matchCubeMeshEntries( cube, ret );
847  return;
848  }
849  const NeuroMesh* nm = dynamic_cast< const NeuroMesh* >( other );
850  if ( nm ) {
851  matchNeuroMeshEntries( nm, ret );
852  return;
853  }
854  cout << "Warning:CylMesh::matchMeshEntries: " <<
855  " unknown mesh type\n";
856 }
857 
858 // Look for end-to-end diffusion, not sideways for now.
859 // Very straightforward but tedious because of the different permutations.
860 // Could readily add cylinder side to other end.
862 vector< VoxelJunction >& ret ) const
863 {
864  const double EPSILON = 1e-3;
865  ret.clear();
866  // Should really estimate the distance from the centre of the smaller
867  // cylinder cap disk to the plane of the larger disk, provided it is
868  // within the radius of the disk. The subsequent calculations are the
869  // same though.
870  double dr1 = // startOfSelf-to-startOfOther
871  distance(x0_ - other->x0_, y0_ - other->y0_, z0_ - other->z0_ );
872  double dr2 = // endOfSelf-to-endOfOther
873  distance(x1_ - other->x1_, y1_ - other->y1_, z1_ - other->z1_ );
874  double dr3 = // endOfSelf-to-startOfOther
875  distance(x1_ - other->x0_, y1_ - other->y0_, z1_ - other->z0_ );
876  double dr4 = // startOfSelf-to-endOfOther
877  distance(x0_ - other->x1_, y0_ - other->y1_, z0_ - other->z1_ );
878 
879  if ( dr1 <= dr2 && dr1 <= dr3 && dr1 <= dr4 ) {
880  if ( ( dr1/totLen_ < EPSILON && dr1/other->totLen_ < EPSILON ) ) {
881  double xda;
882  if ( r0_ < other->r0_ )
883  xda = 2 * r0_ * r0_ * PI / ( diffLength_ + other->diffLength_ );
884  else
885  xda = 2 * other->r0_ * other->r0_ * PI /
886  ( diffLength_ + other->diffLength_ );
887  ret.push_back( VoxelJunction( 0, 0, xda ) );
888  ret.back().first = 0;
889  ret.back().second = 0;
890  ret.back().firstVol = getMeshEntryVolume( 0 );
891  ret.back().secondVol = other->getMeshEntryVolume( 0 );
892  }
893  } else if ( dr2 <= dr3 && dr2 <= dr4 ) {
894  if ( ( dr2/totLen_ < EPSILON && dr2/other->totLen_ < EPSILON ) ) {
895  double xda;
896  if ( r1_ < other->r1_ )
897  xda = 2 * r1_ * r1_ * PI / ( diffLength_ + other->diffLength_ );
898  else
899  xda = 2 * other->r1_ * other->r1_ * PI /
900  ( diffLength_ + other->diffLength_ );
901  ret.push_back( VoxelJunction( numEntries_ - 1,
902  other->numEntries_ - 1, xda ) );
903  ret.back().first = numEntries_;
904  ret.back().second = other->numEntries_ - 1;
905  ret.back().firstVol = getMeshEntryVolume( numEntries_ - 1 );
906  ret.back().secondVol = other->getMeshEntryVolume( other->numEntries_ - 1 );
907  }
908  } else if ( dr3 <= dr4 ) {
909  if ( ( dr3/totLen_ < EPSILON && dr3/other->totLen_ < EPSILON ) ) {
910  double xda;
911  if ( r1_ < other->r0_ )
912  xda = 2 * r1_ * r1_ * PI / ( diffLength_ + other->diffLength_ );
913  else
914  xda = 2 * other->r0_ * other->r0_ * PI /
915  ( diffLength_ + other->diffLength_ );
916  ret.push_back( VoxelJunction( numEntries_ - 1, 0, xda ) );
917  ret.back().first = numEntries_ - 1;
918  ret.back().second = 0;
919  ret.back().firstVol = getMeshEntryVolume( numEntries_ - 1 );
920  ret.back().secondVol = other->getMeshEntryVolume( 0 );
921  }
922  } else {
923  if ( ( dr4/totLen_ < EPSILON && dr4/other->totLen_ < EPSILON ) ) {
924  double xda;
925  if ( r0_ < other->r1_ )
926  xda = 2 * r0_ * r0_ * PI / ( diffLength_ + other->diffLength_ );
927  else
928  xda = 2 * other->r1_ * other->r1_ * PI /
929  ( diffLength_ + other->diffLength_ );
930  ret.push_back( VoxelJunction( 0, other->numEntries_ - 1, xda ));
931  ret.back().first = 0;
932  ret.back().second = other->numEntries_ - 1;
933  ret.back().firstVol = getMeshEntryVolume( 0 );
934  ret.back().secondVol = other->getMeshEntryVolume( other->numEntries_ - 1 );
935  }
936  }
937 }
938 
939 // Select grid volume. Ideally the meshes should be comparable.
940 double CylMesh::selectGridVolume( double h ) const
941 {
942  if ( h > diffLength_ )
943  h = diffLength_;
944  if ( h > r0_ )
945  h = r0_;
946  if ( h > r1_ )
947  h = r1_;
948  h *= surfaceGranularity_;
949  unsigned int num = ceil( diffLength_ / h );
950  h = diffLength_ / num;
951 
952  return h;
953 }
954 
956  const Vec& u, const Vec& v, const Vec& q,
957  double h, double r, vector< double >& area,
958  const CubeMesh* other
959  )
960 {
961  // fine-tune the h spacing so it is integral around circle.
962  // This will cause small errors in area estimate but they will
963  // be anisotropic. The alternative will have large errors toward
964  // 360 degrees, but not elsewhere.
965  unsigned int numAngle = floor( 2.0 * PI * r / h + 0.5 );
966  assert( numAngle > 0 );
967  double dtheta = 2.0 * PI / numAngle;
968  double dArea = h * dtheta * r;
969  // March along points on surface of circle centred at q.
970  for ( unsigned int j = 0; j < numAngle; ++j ) {
971  double theta = j * dtheta;
972  double c = cos( theta );
973  double s = sin( theta );
974  double p0 = q.a0() + r * ( u.a0() * c + v.a0() * s );
975  double p1 = q.a1() + r * ( u.a1() * c + v.a1() * s );
976  double p2 = q.a2() + r * ( u.a2() * c + v.a2() * s );
977  unsigned int index = other->spaceToIndex( p0, p1, p2 );
978  if ( index != CubeMesh::EMPTY )
979  area[index] += dArea;
980  }
981 }
982 
984 vector< VoxelJunction >& ret ) const
985 {
986  const double EPSILON = 1e-18;
987  Vec a( x1_ - x0_, y1_ - y0_, z1_ - z0_ );
988  Vec u;
989  Vec v;
990  a.orthogonalAxes( u, v );
991 
992  double h = selectGridVolume( other->getDx() );
993 
994  unsigned int num = floor( 0.1 + diffLength_ / h );
995  // March along axis of cylinder.
996  // q is the location of the point along axis.
997  for ( unsigned int i = 0; i < numEntries_; ++i ) {
998  vector< double >area( other->getNumEntries(), 0.0 );
999  for ( unsigned int j = 0; j < num; ++j ) {
1000  unsigned int m = i * num + j;
1001  double frac = ( m * h + h/2.0 ) / totLen_;
1002  double q0 = x0_ + a.a0() * frac;
1003  double q1 = y0_ + a.a1() * frac;
1004  double q2 = z0_ + a.a2() * frac;
1005  // get radius of cylinder at this point.
1006  double r = r0_ + ( m * h + h / 2.0 ) * rSlope_;
1007  fillPointsOnCircle( u, v, Vec( q0, q1, q2 ),
1008  h, r, area, other );
1009  }
1010  // Go through all cubeMesh entries and compute diffusion
1011  // cross-section. Assume this is through a membrane, so the
1012  // only factor relevant is area. Not the distance.
1013  for ( unsigned int k = 0; k < area.size(); ++k ) {
1014  if ( area[k] > EPSILON ) {
1015  ret.push_back( VoxelJunction( i, k, area[k] ) );
1016  }
1017  }
1018  }
1019 }
1020 
1022 vector< VoxelJunction >& ret ) const
1023 {
1024 }
1025 
1026 void CylMesh::indexToSpace( unsigned int index,
1027  double& x, double& y, double& z ) const
1028 {
1029  if ( index < numEntries_ ) {
1030  double k = ( index + 0.5 ) / static_cast< double >( numEntries_ );
1031  x = ( x1_ - x0_ ) * k + x0_;
1032  y = ( y1_ - y0_ ) * k + y0_;
1033  z = ( z1_ - z0_ ) * k + z0_;
1034  }
1035 }
1036 
1037 static double dotprd ( double x0, double y0, double z0,
1038  double x1, double y1, double z1 )
1039 {
1040  return x0 * x1 + y0 * y1 + z0 * z1;
1041 }
1042 
1043 
1044 // this is the function that does the actual calculation.
1045 double CylMesh::nearest( double x, double y, double z,
1046  double& linePos, double& r ) const
1047 {
1048  // Consider r0 = x0,y0,z0 and r1 = x1, y1, z1, and r = x,y,z.
1049  // Fraction along cylinder = k
1050  //
1051  // Then, point p along line from r0 to r1 is
1052  // p = k( r0-r1) + r1.
1053  //
1054  // Solving,
1055  // k = (r0 - r1).(r - r1) / (|r0-r1|^2)
1056  //
1057 
1058  double dist = distance( x1_ - x0_, y1_ - y0_, z1_ - z0_ );
1059  double k = dotprd(
1060  x1_ - x0_, y1_ - y0_, z1_ - z0_,
1061  x - x0_, y - y0_, z - z0_ ) / ( dist * dist );
1062 
1063  // x2, y2, z2 are the coords of the nearest point.
1064  double x2 = k * (x1_ - x0_) + x0_;
1065  double y2 = k * (y1_ - y0_) + y0_;
1066  double z2 = k * (z1_ - z0_) + z0_;
1067 
1068  double ret = distance( x - x2, y - y2, z - z2 );
1069  linePos = k;
1070  r = r0_ + k * numEntries_ * rSlope_;
1071  return ret;
1072 }
1073 
1074 // This function returns the index.
1075 double CylMesh::nearest( double x, double y, double z,
1076  unsigned int& index ) const
1077 {
1078  double k = 0.0;
1079  double r;
1080  double ret = nearest( x, y, z, k, r );
1081  if ( k < 0.0 ) {
1082  ret = -ret;
1083  index = 0;
1084  } else if ( k > 1.0 ) {
1085  ret = -ret;
1086  index = numEntries_ - 1;
1087  } else { // Inside length of cylinder, now is it inside radius?
1088  index = k * numEntries_;
1089  double ri = r0_ + (index + 0.5) * rSlope_;
1090  if ( ret > ri )
1091  ret = -ret;
1092  }
1093  return ret;
1094 }
1095 
1096 
1097 /*
1098 bool isOnSurface( double x, double y, double z,
1099  double dx, double dy, double dz,
1100  unsigned int &index, double& adx )
1101 {
1102  double len = distance( x1_ - x0_, y1_ - y0_, z1_ - z0_ );
1103  double k = dotprd(
1104  x1_ - x0_, y1_ - y0_, z1_ - z0_,
1105  x - x0_, y - y0_, z - z0_ ) / len;
1106 
1107  // x2, y2, z2 are the coords of the nearest point.
1108  double x2 = k * (x1_ - x0_) + x0_;
1109  double y2 = k * (y1_ - y0_) + y0_;
1110  double z2 = k * (z1_ - z0_) + z0_;
1111 
1112  double ret = distance( x - x2, y - y2, z - z2 );
1113 
1114  double cubeRange = sqrt(dx*dx + dy*dy + dz*dz);
1115 
1116  // Now we check if the distance is definitely too far off for the
1117  // passed in point
1118  if ( k < -dx/2 || k > len + dx/2 ) // past the end.
1119  return false;
1120 
1121  double ri = k * rSlope_; // local cylinder radius.
1122 
1123  if ( ret > ri + cubeRange || ret < ri - cubeRange )
1124  return false;
1125 
1126  // OK, now we need to find the plane of intersection of the cylinder
1127  // with the cuboid. To make it easier, assume it is flat. We already
1128  // know the vector from the middle of the cuboid to the nearest
1129  // cylinder point. Treat it as the normal to the intersection plane.
1130  // We need: : is the plane inside the cube?
1131  // What is the area of the plane till its intersection with the cube?
1132 
1133 }
1134 
1135 */
static const Cinfo * initCinfo()
Definition: ChemCompt.cpp:25
double surfaceGranularity_
Length constant for diffusion. Equal to dx.
Definition: CylMesh.h:185
vector< double > getDiffusionArea(unsigned int fid) const
Virtual function to return diffusion X-section area.
Definition: CylMesh.cpp:520
void updateCoords(const Eref &e, const vector< double > &childConcs)
Definition: CylMesh.cpp:205
double a0() const
Definition: Vec.h:34
double nearest(double x, double y, double z, unsigned int &index) const
Definition: CylMesh.cpp:1075
void innerResetStencil()
virtual func implemented here.
Definition: MeshCompt.cpp:49
double getY0(const Eref &e) const
Definition: CylMesh.cpp:259
unsigned int numEntries_
Definition: CylMesh.h:163
static const Cinfo * initCinfo()
Definition: CylMesh.cpp:27
vector< double > getCoordinates(unsigned int fid) const
Virtual function to return coords of mesh Entry.
Definition: CylMesh.cpp:489
unsigned int getMeshType(unsigned int fid) const
Virtual function to return MeshType of specified entry.
Definition: CylMesh.cpp:421
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
Definition: Dinfo.h:60
double x0_
Definition: CylMesh.h:167
void addRow(unsigned int index, const vector< double > &entry, const vector< unsigned int > &colIndex)
Definition: MeshCompt.cpp:98
void innerHandleNodeInfo(const Eref &e, unsigned int numNodes, unsigned int numThreads)
Definition: CylMesh.cpp:591
double extendedMeshEntryVolume(unsigned int fid) const
Virtual function to return volume of mesh Entry, including.
Definition: MeshCompt.cpp:36
void setDiffLength(const Eref &e, double v)
Definition: CylMesh.cpp:392
void transmitChange(const Eref &e)
Definition: CylMesh.cpp:741
double getDx() const
Definition: CubeMesh.cpp:507
static const Cinfo * cylMeshCinfo
Definition: CylMesh.cpp:164
double a2() const
Definition: Vec.h:40
void indexToSpace(unsigned int index, double &x, double &y, double &z) const
Definition: CylMesh.cpp:1026
const int numEntries
Definition: proc.cpp:60
void setY1(const Eref &e, double v)
Definition: CylMesh.cpp:304
vector< double > getCoords(const Eref &e) const
Definition: CylMesh.cpp:372
double r1_
Radius at one end.
Definition: CylMesh.h:176
double y1_
coords
Definition: CylMesh.h:172
double z0_
coords
Definition: CylMesh.h:169
bool isToroid_
Definition: CylMesh.h:165
static double dotprd(double x0, double y0, double z0, double x1, double y1, double z1)
Definition: CylMesh.cpp:1037
CylMesh()
Definition: CylMesh.cpp:169
unsigned int getNumEntries() const
Definition: ChemCompt.cpp:390
double getTotLength() const
Definition: CylMesh.cpp:406
unsigned int innerGetNumEntries() const
Definition: CylMesh.cpp:615
void innerHandleRequestMeshStats(const Eref &e, const SrcFinfo2< unsigned int, vector< double > > *meshStatsFinfo)
More inherited virtual funcs: request comes in for mesh stats.
Definition: CylMesh.cpp:583
double getX1(const Eref &e) const
Definition: CylMesh.cpp:299
unsigned int getMeshDimensions(unsigned int fid) const
Virtual function to return dimensions of specified entry.
Definition: CylMesh.cpp:430
bool doubleEq(double x, double y)
Definition: doubleEq.cpp:16
double lenSlope_
Utility value: dr/dx.
Definition: CylMesh.h:189
Definition: Vec.h:13
void setZ0(const Eref &e, double v)
Definition: CylMesh.cpp:264
double getMeshEntryVolume(unsigned int fid) const
Virtual function to return volume of mesh Entry.
Definition: CylMesh.cpp:477
void matchNeuroMeshEntries(const NeuroMesh *other, vector< VoxelJunction > &ret) const
Definition: CylMesh.cpp:1021
~CylMesh()
Definition: CylMesh.cpp:191
static double distance(double x, double y, double z)
Definition: ChemCompt.cpp:422
void setX0(const Eref &e, double v)
Definition: CylMesh.cpp:238
void innerSetNumEntries(unsigned int n)
Inherited virtual func.
Definition: CylMesh.cpp:623
Definition: MeshEntry.h:20
void matchMeshEntries(const ChemCompt *other, vector< VoxelJunction > &ret) const
Definition: CylMesh.cpp:827
void setX1(const Eref &e, double v)
Definition: CylMesh.cpp:291
void getChildConcs(const Eref &e, vector< double > &childConcs) const
Definition: ChemCompt.cpp:264
double getR1(const Eref &e) const
Definition: CylMesh.cpp:338
const vector< double > & getVoxelArea() const
Definition: CylMesh.cpp:694
bool useCaps_
Definition: CylMesh.h:164
void setR0(const Eref &e, double v)
Definition: CylMesh.cpp:277
double r0_
coords
Definition: CylMesh.h:175
double extendedMeshEntryVolume(unsigned int fid) const
Volume of mesh Entry including abutting diff-coupled voxels.
Definition: CylMesh.cpp:569
Definition: Eref.h:26
double getR0(const Eref &e) const
Definition: CylMesh.cpp:285
vector< double > getDiffusionScaling(unsigned int fid) const
Virtual function to return scale factor for diffusion. 1 here.
Definition: CylMesh.cpp:556
void buildStencil()
Definition: CylMesh.cpp:785
double rSlope_
Utility value: Total length of cylinder.
Definition: CylMesh.h:188
double getZ0(const Eref &e) const
Definition: CylMesh.cpp:272
bool vSetVolumeNotRates(double volume)
Inherited virtual. Resizes len and dia of each voxel.
Definition: CylMesh.cpp:722
unsigned int setChildConcs(const Eref &e, const vector< double > &childConcs, unsigned int start) const
Definition: ChemCompt.cpp:288
double totLen_
Definition: CylMesh.h:187
vector< unsigned int > getParentVoxel() const
Inherited virtual, do nothing for now.
Definition: CylMesh.cpp:656
double getY1(const Eref &e) const
Definition: CylMesh.cpp:312
static unsigned int numNodes
double x1_
coords
Definition: CylMesh.h:171
const vector< double > & vGetVoxelMidpoint() const
Virtual func so that derived classes can return voxel midpoint.
Definition: CylMesh.cpp:676
double z1_
coords
Definition: CylMesh.h:173
void fillPointsOnCircle(const Vec &u, const Vec &v, const Vec &q, double h, double r, vector< double > &area, const CubeMesh *other)
Definition: CylMesh.cpp:955
double diffLength_
Radius at other end.
Definition: CylMesh.h:178
void setR1(const Eref &e, double v)
Definition: CylMesh.cpp:330
void matchCubeMeshEntries(const CubeMesh *other, vector< VoxelJunction > &ret) const
Definition: CylMesh.cpp:983
double getX0(const Eref &e) const
Definition: CylMesh.cpp:246
static const unsigned int EMPTY
Definition: CubeMesh.h:285
const double PI
Definition: consts.cpp:12
const vector< double > & getVoxelLength() const
Definition: CylMesh.cpp:707
void orthogonalAxes(Vec &u, Vec &v) const
Generates vectors u and v to form a mutually orthogonal system.
Definition: Vec.cpp:41
const vector< double > & vGetVoxelVolume() const
Virtual func so that derived classes can pass voxel volume back.
Definition: CylMesh.cpp:667
double y0_
coords
Definition: CylMesh.h:168
void setY0(const Eref &e, double v)
Definition: CylMesh.cpp:251
void setZ1(const Eref &e, double v)
Definition: CylMesh.cpp:317
double getDiffLength(const Eref &e) const
Definition: CylMesh.cpp:400
void setStencilSize(unsigned int numRows, unsigned int numCols)
Definition: MeshCompt.cpp:106
double vGetEntireVolume() const
Inherited virtual. Returns entire volume of compartment.
Definition: CylMesh.cpp:714
void matchCylMeshEntries(const CylMesh *other, vector< VoxelJunction > &ret) const
Definition: CylMesh.cpp:861
void innerBuildDefaultMesh(const Eref &e, double volume, unsigned int numEntries)
Virtual func to make a mesh with specified Volume and numEntries.
Definition: CylMesh.cpp:641
double a1() const
Definition: Vec.h:37
unsigned int innerGetDimensions() const
Definition: CylMesh.cpp:411
void flipRet(vector< VoxelJunction > &ret) const
Utility function for swapping first and second in VoxelJunctions.
Definition: ChemCompt.cpp:406
#define EPSILON
Definition: MatrixOps.h:28
void matchMeshEntries(const ChemCompt *other, vector< VoxelJunction > &ret) const
Definition: EndoMesh.cpp:420
void setCoords(const Eref &e, vector< double > v)
Definition: CylMesh.cpp:363
Definition: Cinfo.h:18
double getZ1(const Eref &e) const
Definition: CylMesh.cpp:325
double selectGridVolume(double h) const
Definition: CylMesh.cpp:940
void innerSetCoords(const Eref &e, const vector< double > &v)
Definition: CylMesh.cpp:343
Definition: Finfo.h:12