MOOSE - Multiscale Object Oriented Simulation Environment
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
HSolvePassive.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) 2003-2007 Upinder S. Bhalla, Niraj Dudani 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 "HSolvePassive.h"
11 
12 extern ostream& operator <<( ostream& s, const HinesMatrix& m );
13 
14 void HSolvePassive::setup( Id seed, double dt )
15 {
16  clear();
17  dt_ = dt;
18  walkTree( seed );
19  initialize();
20  storeTree();
22 }
23 
25 {
26  updateMatrix();
29 }
30 
32 // Setup of data structures.
34 
36 {
37  dt_ = 0.0;
38  compartment_.clear();
39  compartmentId_.clear();
40  V_.clear();
41  tree_.clear();
42  inject_.clear();
43 }
44 
46 {
47  //~ // Dirty call to explicitly call the compartments reinitFunc.
48  //~ // Should be removed eventually, and replaced with a cleaner way to
49  //~ // initialize the model being read.
50  //~ HSolveUtils::initialize( seed );
51 
52  // Find leaf node
53  Id previous;
54  vector< Id > adjacent;
55  HSolveUtils::adjacent( seed, adjacent );
56  if ( adjacent.size() > 1 )
57  while ( !adjacent.empty() )
58  {
59  previous = seed;
60  seed = adjacent[ 0 ];
61 
62  adjacent.clear();
63  HSolveUtils::adjacent( seed, previous, adjacent );
64  }
65 
66  // Depth-first search
67  vector< vector< Id > > cstack;
68  Id above;
69  Id current;
70  cstack.resize( 1 );
71  cstack[ 0 ].push_back( seed );
72  while ( !cstack.empty() )
73  {
74  vector< Id >& top = cstack.back();
75 
76  if ( top.empty() )
77  {
78  cstack.pop_back();
79  if ( !cstack.empty() )
80  cstack.back().pop_back();
81  }
82  else
83  {
84  if ( cstack.size() > 1 )
85  above = cstack[ cstack.size() - 2 ].back();
86 
87  current = top.back();
88  compartmentId_.push_back( current );
89 
90  cstack.resize( cstack.size() + 1 );
91  HSolveUtils::adjacent( current, above, cstack.back() );
92  }
93  }
94 
95  // Compartments get ordered according to their hines' indices once this
96  // list is reversed.
97  reverse( compartmentId_.begin(), compartmentId_.end() );
98 }
99 
101 {
102  nCompt_ = compartmentId_.size();
103 
104  double Vm, Cm, Em, Rm, inject;
105  double EmLeak, GmLeak;
106  double EmGmThev, GmThev;
107 
108  vector< Id > leakage;
109  vector< Id >::iterator ileakage;
110 
111  for ( unsigned int ic = 0; ic < compartmentId_.size(); ++ic )
112  {
113  Id cc = compartmentId_[ ic ];
114 
115  Vm = Field< double >::get( cc, "Vm" );
116  Cm = Field< double >::get( cc, "Cm" );
117  Em = Field< double >::get( cc, "Em" );
118  Rm = Field< double >::get( cc, "Rm" );
119  inject = Field< double >::get( cc, "inject" );
120  V_.push_back( Vm );
121 
122  /*
123  * If there are 'n' leakage channels with reversal potentials:
124  * E[ 1 ] ... E[ n ]
125  * and resistances:
126  * R[ 1 ] ... R[ n ]
127  * respectively, then the membrane circuit can be represented by the
128  * Thevenin equivalent circuit with:
129  *
130  * R_thevenin = 1 / sum( 1 / R[ i ] )
131  * = 1 / sum( G[ i ] )
132  * E_thevenin = sum( E[ i ] / R[ i ] ) * R_thevenin
133  * = sum( E[ i ] * G[ i ] ) * R_thevenin
134  *
135  * Here we have to add original membrane potential Em as E[ 0 ] and
136  * resistance Rm as R[ 0 ].
137  */
138  GmThev = 1.0 / Rm;
139  EmGmThev = Em / Rm;
140 
142  for ( ileakage = leakage.begin();
143  ileakage != leakage.end();
144  ileakage++ )
145  {
146  EmLeak = Field< double >::get( *ileakage, "Ek" );
147  GmLeak = Field< double >::get( *ileakage, "Gk" );
148  GmThev += GmLeak;
149  EmGmThev += EmLeak * GmLeak;
150  }
151 
152 // RmThev = 1.0 / GmThev;
153 
154  CompartmentStruct compartment;
155  compartment.CmByDt = 2.0 * Cm / dt_;
156  compartment.EmByRm = EmGmThev;
157  compartment_.push_back( compartment );
158 
159  if ( inject != 0.0 )
160  {
161  inject_[ ic ].injectVarying = 0.0;
162  inject_[ ic ].injectBasal = inject;
163  }
164  }
165 }
166 
168 {
169  double Ra, Rm, Cm, Em, initVm;
170 
171  // Create a map from the MOOSE Id to Hines' index.
172  map< Id, unsigned int > hinesIndex;
173  for ( unsigned int ic = 0; ic < nCompt_; ++ic )
174  hinesIndex[ compartmentId_[ ic ] ] = ic;
175 
176  vector< Id > childId;
177  vector< Id >::iterator child;
178 
179  vector< Id >::iterator ic;
180 
181  for ( ic = compartmentId_.begin(); ic != compartmentId_.end(); ++ic )
182  {
183  childId.clear();
184 
185  HSolveUtils::children( *ic, childId );
186  Ra = Field< double >::get( *ic, "Ra" );
187  Cm = Field< double >::get( *ic, "Cm" );
188  Rm = Field< double >::get( *ic, "Rm" );
189  Em = Field< double >::get( *ic, "Em" );
190  initVm = Field< double >::get( *ic, "initVm" );
191 
192  TreeNodeStruct node;
193  // Push hines' indices of children
194  for ( child = childId.begin(); child != childId.end(); ++child )
195  node.children.push_back( hinesIndex[ *child ] );
196 
197  node.Ra = Ra;
198  node.Rm = Rm;
199  node.Cm = Cm;
200  node.Em = Em;
201  node.initVm = initVm;
202 
203  tree_.push_back( node );
204  }
205 }
206 
208 // Numerical integration.
210 
212 {
213  /*
214  * Copy contents of HJCopy_ into HJ_. Cannot do a vector assign() because
215  * iterators to HJ_ get invalidated in MS VC++
216  */
217  if ( HJ_.size() != 0 )
218  memcpy( &HJ_[ 0 ], &HJCopy_[ 0 ], sizeof( double ) * HJ_.size() );
219 
220  vector< double >::iterator ihs = HS_.begin();
221  vector< double >::iterator iv = V_.begin();
222 
223  vector< CompartmentStruct >::iterator ic;
224  for ( ic = compartment_.begin(); ic != compartment_.end(); ++ic )
225  {
226  *ihs = *( 2 + ihs );
227  *( 3 + ihs ) = *iv * ic->CmByDt + ic->EmByRm;
228 
229  ihs += 4, ++iv;
230  }
231 
232  map< unsigned int, InjectStruct >::iterator inject;
233  for ( inject = inject_.begin(); inject != inject_.end(); inject++ )
234  {
235  unsigned int ic = inject->first;
236  InjectStruct& value = inject->second;
237 
238  HS_[ 4 * ic + 3 ] += value.injectVarying + value.injectBasal;
239 
240  value.injectVarying = 0.0;
241  }
242 
243  stage_ = 0; // Update done.
244 }
245 
247 {
248  unsigned int ic = 0;
249  vector< double >::iterator ihs = HS_.begin();
250  vector< vdIterator >::iterator iop = operand_.begin();
251  vector< JunctionStruct >::iterator junction;
252 
253  double pivot;
254  double division;
255  unsigned int index;
256  unsigned int rank;
257  for ( junction = junction_.begin();
258  junction != junction_.end();
259  junction++ )
260  {
261  index = junction->index;
262  rank = junction->rank;
263 
264  while ( ic < index )
265  {
266  *( ihs + 4 ) -= *( ihs + 1 ) / *ihs **( ihs + 1 );
267  *( ihs + 7 ) -= *( ihs + 1 ) / *ihs **( ihs + 3 );
268 
269  ++ic, ihs += 4;
270  }
271 
272  pivot = *ihs;
273  if ( rank == 1 )
274  {
275  vdIterator j = *iop;
276  vdIterator s = *( iop + 1 );
277 
278  division = *( j + 1 ) / pivot;
279  *( s ) -= division **j;
280  *( s + 3 ) -= division **( ihs + 3 );
281 
282  iop += 3;
283  }
284  else if ( rank == 2 )
285  {
286  vdIterator j = *iop;
287  vdIterator s;
288 
289  s = *( iop + 1 );
290  division = *( j + 1 ) / pivot;
291  *( s ) -= division **j;
292  *( j + 4 ) -= division **( j + 2 );
293  *( s + 3 ) -= division **( ihs + 3 );
294 
295  s = *( iop + 3 );
296  division = *( j + 3 ) / pivot;
297  *( j + 5 ) -= division **j;
298  *( s ) -= division **( j + 2 );
299  *( s + 3 ) -= division **( ihs + 3 );
300 
301  iop += 5;
302  }
303  else
304  {
305  vector< vdIterator >::iterator
306  end = iop + 3 * rank * ( rank + 1 );
307  for ( ; iop < end; iop += 3 )
308  **iop -= **( iop + 2 ) / pivot ***( iop + 1 );
309  }
310 
311  ++ic, ihs += 4;
312  }
313 
314  while ( ic < nCompt_ - 1 )
315  {
316  *( ihs + 4 ) -= *( ihs + 1 ) / *ihs **( ihs + 1 );
317  *( ihs + 7 ) -= *( ihs + 1 ) / *ihs **( ihs + 3 );
318 
319  ++ic, ihs += 4;
320  }
321 
322  stage_ = 1; // Forward elimination done.
323 }
324 
326 {
327  int ic = nCompt_ - 1;
328  vector< double >::reverse_iterator ivmid = VMid_.rbegin();
329  vector< double >::reverse_iterator iv = V_.rbegin();
330  vector< double >::reverse_iterator ihs = HS_.rbegin();
331  vector< vdIterator >::reverse_iterator iop = operand_.rbegin();
332  vector< vdIterator >::reverse_iterator ibop = backOperand_.rbegin();
333  vector< JunctionStruct >::reverse_iterator junction;
334 
335  *ivmid = *ihs / *( ihs + 3 );
336  *iv = 2 * *ivmid - *iv;
337  --ic, ++ivmid, ++iv, ihs += 4;
338 
339  int index;
340  int rank;
341  for ( junction = junction_.rbegin();
342  junction != junction_.rend();
343  junction++ )
344  {
345  index = junction->index;
346  rank = junction->rank;
347 
348  while ( ic > index )
349  {
350  *ivmid = ( *ihs - *( ihs + 2 ) **( ivmid - 1 ) ) / *( ihs + 3 );
351  *iv = 2 * *ivmid - *iv;
352 
353  --ic, ++ivmid, ++iv, ihs += 4;
354  }
355 
356  if ( rank == 1 )
357  {
358  *ivmid = ( *ihs - **iop ***( iop + 2 ) ) / *( ihs + 3 );
359 
360  iop += 3;
361  }
362  else if ( rank == 2 )
363  {
364  vdIterator v0 = *( iop );
365  vdIterator v1 = *( iop + 2 );
366  vdIterator j = *( iop + 4 );
367 
368  *ivmid = ( *ihs
369  - *v0 **( j + 2 )
370  - *v1 **j
371  ) / *( ihs + 3 );
372 
373  iop += 5;
374  }
375  else
376  {
377  *ivmid = *ihs;
378  for ( int i = 0; i < rank; ++i )
379  {
380  *ivmid -= **ibop ***( ibop + 1 );
381  ibop += 2;
382  }
383  *ivmid /= *( ihs + 3 );
384 
385  iop += 3 * rank * ( rank + 1 );
386  }
387 
388  *iv = 2 * *ivmid - *iv;
389  --ic, ++ivmid, ++iv, ihs += 4;
390  }
391 
392  while ( ic >= 0 )
393  {
394  *ivmid = ( *ihs - *( ihs + 2 ) **( ivmid - 1 ) ) / *( ihs + 3 );
395  *iv = 2 * *ivmid - *iv;
396 
397  --ic, ++ivmid, ++iv, ihs += 4;
398  }
399 
400  stage_ = 2; // Backward substitution done.
401 }
402 
404 // Public interface.
406 
407 double HSolvePassive::getV( unsigned int row ) const
408 {
409  return V_[ row ];
410 }
411 
413 
414 #ifdef DO_UNIT_TESTS
415 
416 //~ #include "../element/Neutral.h"
417 //~ #include "../utility/utility.h"
418 //~ #include <sstream>
419 
420 #include <limits>
430 template< class T >
431 bool isClose( T a, T b, T tolerance )
432 {
433  T epsilon = std::numeric_limits< T >::epsilon();
434 
435  if ( a == b )
436  return true;
437 
438  if ( a == 0 || b == 0 )
439  return ( fabs( a - b ) < tolerance * epsilon );
440 
441  return (
442  fabs( ( a - b ) / a ) < tolerance * epsilon
443  &&
444  fabs( ( a - b ) / b ) < tolerance * epsilon
445  );
446 }
447 
448 #include <sstream>
449 #include "../shell/Shell.h"
450 #include "../basecode/global.h"
451 #include "TestHSolve.h"
452 void testHSolvePassive()
453 {
454 // TEST_BEGIN;
455  Shell* shell = reinterpret_cast< Shell* >( Id().eref().data() );
456 
457  vector< int* > childArray;
458  vector< unsigned int > childArraySize;
459 
480  int childArray_1[ ] =
481  {
482  /* c0 */ -1,
483  /* c1 */ -1, 0,
484  /* c2 */ -1, 1,
485  /* c3 */ -1,
486  /* c4 */ -1, 3,
487  /* c5 */ -1,
488  /* c6 */ -1, 5,
489  /* c7 */ -1, 4, 6,
490  /* c8 */ -1, 7,
491  /* c9 */ -1, 8,
492  /* c10 */ -1,
493  /* c11 */ -1, 10,
494  /* c12 */ -1,
495  /* c13 */ -1, 12,
496  /* c14 */ -1, 11, 13,
497  /* c15 */ -1, 14, 16,
498  /* c16 */ -1, 17,
499  /* c17 */ -1, 2, 9, 18,
500  /* c18 */ -1, 19,
501  /* c19 */ -1,
502  };
503 
504  childArray.push_back( childArray_1 );
505  childArraySize.push_back( sizeof( childArray_1 ) / sizeof( int ) );
506 
519  int childArray_2[ ] =
520  {
521  /* c0 */ -1,
522  /* c1 */ -1,
523  /* c2 */ -1, 0, 1, 3,
524  /* c3 */ -1,
525  };
526 
527  childArray.push_back( childArray_2 );
528  childArraySize.push_back( sizeof( childArray_2 ) / sizeof( int ) );
529 
542  int childArray_3[ ] =
543  {
544  /* c0 */ -1, 2,
545  /* c1 */ -1,
546  /* c2 */ -1, 1, 3,
547  /* c3 */ -1,
548  };
549 
550  childArray.push_back( childArray_3 );
551  childArraySize.push_back( sizeof( childArray_3 ) / sizeof( int ) );
552 
565  int childArray_4[ ] =
566  {
567  /* c0 */ -1,
568  /* c1 */ -1,
569  /* c2 */ -1, 0, 1,
570  /* c3 */ -1, 2,
571  };
572 
573  childArray.push_back( childArray_4 );
574  childArraySize.push_back( sizeof( childArray_4 ) / sizeof( int ) );
575 
589  int childArray_5[ ] =
590  {
591  /* c0 */ -1,
592  /* c1 */ -1, 2,
593  /* c2 */ -1, 0, 4,
594  /* c3 */ -1,
595  /* c4 */ -1, 3, 5,
596  /* c5 */ -1,
597  };
598 
599  childArray.push_back( childArray_5 );
600  childArraySize.push_back( sizeof( childArray_5 ) / sizeof( int ) );
601 
615  int childArray_6[ ] =
616  {
617  /* c0 */ -1,
618  /* c1 */ -1,
619  /* c2 */ -1,
620  /* c3 */ -1, 4,
621  /* c4 */ -1, 0, 1, 2, 5, 6,
622  /* c5 */ -1,
623  /* c6 */ -1,
624  };
625 
626  childArray.push_back( childArray_6 );
627  childArraySize.push_back( sizeof( childArray_6 ) / sizeof( int ) );
628 
633  int childArray_7[ ] =
634  {
635  /* c0 */ -1,
636  };
637 
638  childArray.push_back( childArray_7 );
639  childArraySize.push_back( sizeof( childArray_7 ) / sizeof( int ) );
640 
645  int childArray_8[ ] =
646  {
647  /* c0 */ -1,
648  /* c1 */ -1, 0, 2,
649  /* c2 */ -1,
650  };
651 
652  childArray.push_back( childArray_8 );
653  childArraySize.push_back( sizeof( childArray_8 ) / sizeof( int ) );
654 
659  int childArray_9[ ] =
660  {
661  /* c0 */ -1, 1,
662  /* c1 */ -1, 2,
663  /* c2 */ -1,
664  };
665 
666  childArray.push_back( childArray_9 );
667  childArraySize.push_back( sizeof( childArray_9 ) / sizeof( int ) );
668 
670  // Run tests
672  /*
673  * Solver instance.
674  */
675  HSolvePassive HP;
676 
677  /*
678  * This is the full reference matrix which will be compared to its sparse
679  * implementation.
680  */
681  vector< vector< double > > matrix;
682 
683  /*
684  * Model details.
685  */
686  double dt = 1.0;
687  vector< TreeNodeStruct > tree;
688  vector< double > Em;
689  vector< double > B;
690  vector< double > V;
691  vector< double > VMid;
692 
693  /*
694  * Loop over cells.
695  */
696  int i;
697  int j;
698  //~ bool success;
699  int nCompt;
700  int* array;
701  unsigned int arraySize;
702  for ( unsigned int cell = 0; cell < childArray.size(); cell++ )
703  {
704  array = childArray[ cell ];
705  arraySize = childArraySize[ cell ];
706  nCompt = count( array, array + arraySize, -1 );
707 
709  // Prepare local information on cell
711  tree.clear();
712  tree.resize( nCompt );
713  Em.clear();
714  V.clear();
715  for ( i = 0; i < nCompt; i++ )
716  {
717  tree[ i ].Ra = 15.0 + 3.0 * i;
718  tree[ i ].Rm = 45.0 + 15.0 * i;
719  tree[ i ].Cm = 500.0 + 200.0 * i * i;
720  Em.push_back( -0.06 );
721  V.push_back( -0.06 + 0.01 * i );
722  }
723 
724  int count = -1;
725  for ( unsigned int a = 0; a < arraySize; a++ )
726  if ( array[ a ] == -1 )
727  count++;
728  else
729  tree[ count ].children.push_back( array[ a ] );
730 
732  // Create cell inside moose; setup solver.
734  Id n = shell->doCreate( "Neutral", Id(), "n", 1 );
735 
736  vector< Id > c( nCompt );
737  for ( i = 0; i < nCompt; i++ )
738  {
739  ostringstream name;
740  name << "c" << i;
741  c[ i ] = shell->doCreate( "Compartment", n, name.str() , 1);
742 
743  Field< double >::set( c[ i ], "Ra", tree[ i ].Ra );
744  Field< double >::set( c[ i ], "Rm", tree[ i ].Rm );
745  Field< double >::set( c[ i ], "Cm", tree[ i ].Cm );
746  Field< double >::set( c[ i ], "Em", Em[ i ] );
747  Field< double >::set( c[ i ], "initVm", V[ i ] );
748  Field< double >::set( c[ i ], "Vm", V[ i ] );
749  }
750 
751  for ( i = 0; i < nCompt; i++ )
752  {
753  vector< unsigned int >& child = tree[ i ].children;
754  for ( j = 0; j < ( int )( child.size() ); j++ )
755  {
756  ObjId mid = shell->doAddMsg(
757  "Single", c[ i ], "axial", c[ child[ j ] ], "raxial" );
758  ASSERT( ! mid.bad(), "Creating test model" );
759  }
760  }
761 
762  HP.setup( c[ 0 ], dt );
763 
764  /*
765  * Here we check if the cell was read in correctly by the solver.
766  * This test only checks if all the created compartments were read in.
767  * It doesn't check if they have been assigned hines' indices correctly.
768  */
769  vector< Id >& hc = HP.compartmentId_;
770  ASSERT( ( int )( hc.size() ) == nCompt, "Tree traversal" );
771  for ( i = 0; i < nCompt; i++ )
772  ASSERT(
773  find( hc.begin(), hc.end(), c[ i ] ) != hc.end(), "Tree traversal"
774  );
775 
777  // Setup local matrix
779 
780  /*
781  * First we need to ensure that the hines' indices for the local model
782  * and those inside the solver match. If the numbering is different,
783  * then the matrices will not agree.
784  *
785  * In the following, we find out the indices assigned by the solver,
786  * and impose them on the local data structures.
787  */
788 
789  // Figure out new indices
790  vector< unsigned int > permutation( nCompt );
791  for ( i = 0; i < nCompt; i++ )
792  {
793  unsigned int newIndex =
794  find( hc.begin(), hc.end(), c[ i ] ) - hc.begin();
795  permutation[ i ] = newIndex;
796  }
797 
798  // Shuffle compartment properties according to new order
799  permute< TreeNodeStruct >( tree, permutation );
800  permute< double >( Em, permutation );
801  permute< double >( V, permutation );
802 
803  // Update indices of children
804  for ( i = 0; i < nCompt; i++ )
805  {
806  vector< unsigned int >& child = tree[ i ].children;
807  for ( j = 0; j < ( int )( child.size() ); j++ )
808  child[ j ] = permutation[ child[ j ] ];
809  }
810 
811  // Create local reference matrix
812  makeFullMatrix( tree, dt, matrix );
813  VMid.resize( nCompt );
814  B.resize( nCompt );
815 
816  vector< vector< double > > matrixCopy;
817  matrixCopy.assign( matrix.begin(), matrix.end() );
818 
820  // Run comparisons
822  double tolerance;
823 
824  /*
825  * Compare initial matrices
826  */
827 
828  tolerance = 2.0;
829 
830  for ( i = 0; i < nCompt; ++i )
831  for ( j = 0; j < nCompt; ++j )
832  {
833  ostringstream error;
834  error << "Testing matrix construction:"
835  << " Cell# " << cell + 1
836  << " A(" << i << ", " << j << ")";
837  ASSERT (
838  isClose< double >( HP.getA( i, j ), matrix[ i ][ j ], tolerance ),
839  error.str()
840  );
841  }
842 
843  /*
844  *
845  * Gaussian elimination
846  *
847  */
848 
849  tolerance = 4.0; // ratio to machine epsilon
850 
851  for ( int pass = 0; pass < 2; pass++ )
852  {
853  /*
854  * First update terms in the equation. This involves setting up the B
855  * in Ax = B, using the latest voltage values. Also, the coefficients
856  * stored in A have to be restored to their original values, since
857  * the matrix is modified at the end of every pass of gaussian
858  * elimination.
859  */
860 
861  // Do so in the solver..
862  HP.updateMatrix();
863 
864  // ..locally..
865  matrix.assign( matrixCopy.begin(), matrixCopy.end() );
866 
867  for ( i = 0; i < nCompt; i++ )
868  B[ i ] =
869  V[ i ] * tree[ i ].Cm / ( dt / 2.0 ) +
870  Em[ i ] / tree[ i ].Rm;
871 
872  // ..and compare B.
873  for ( i = 0; i < nCompt; ++i )
874  {
875  ostringstream error;
876  error << "Updating right-hand side values:"
877  << " Pass " << pass
878  << " Cell# " << cell + 1
879  << " B(" << i << ")";
880  ASSERT (
881  isClose< double >( HP.getB( i ), B[ i ], tolerance ),
882  error.str()
883  );
884  }
885 
886  /*
887  * Forward elimination..
888  */
889 
890  // ..in solver..
891  HP.forwardEliminate();
892 
893  // ..and locally..
894  int k;
895  for ( i = 0; i < nCompt - 1; i++ )
896  for ( j = i + 1; j < nCompt; j++ )
897  {
898  double div = matrix[ j ][ i ] / matrix[ i ][ i ];
899  for ( k = 0; k < nCompt; k++ )
900  matrix[ j ][ k ] -= div * matrix[ i ][ k ];
901  B[ j ] -= div * B[ i ];
902  }
903 
904  // ..then compare A..
905  for ( i = 0; i < nCompt; ++i )
906  for ( j = 0; j < nCompt; ++j )
907  {
908  ostringstream error;
909  error << "Forward elimination:"
910  << " Pass " << pass
911  << " Cell# " << cell + 1
912  << " A(" << i << ", " << j << ")";
913  ASSERT (
914  isClose< double >( HP.getA( i, j ), matrix[ i ][ j ], tolerance ),
915  error.str()
916  );
917  }
918 
919  // ..and also B.
920  for ( i = 0; i < nCompt; ++i )
921  {
922  ostringstream error;
923  error << "Forward elimination:"
924  << " Pass " << pass
925  << " Cell# " << cell + 1
926  << " B(" << i << ")";
927  ASSERT (
928  isClose< double >( HP.getB( i ), B[ i ], tolerance ),
929  error.str()
930  );
931  }
932 
933  /*
934  * Backward substitution..
935  */
936 
937  // ..in solver..
938  HP.backwardSubstitute();
939 
940  // ..and full back-sub on local matrix equation..
941  for ( i = nCompt - 1; i >= 0; i-- )
942  {
943  VMid[ i ] = B[ i ];
944 
945  for ( j = nCompt - 1; j > i; j-- )
946  VMid[ i ] -= VMid[ j ] * matrix[ i ][ j ];
947 
948  VMid[ i ] /= matrix[ i ][ i ];
949 
950  V[ i ] = 2 * VMid[ i ] - V[ i ];
951  }
952 
953  // ..and then compare VMid.
954  for ( i = nCompt - 1; i >= 0; i-- )
955  {
956  ostringstream error;
957  error << "Back substitution:"
958  << " Pass " << pass
959  << " Cell# " << cell + 1
960  << " VMid(" << i << ")";
961  ASSERT (
962  isClose< double >( HP.getVMid( i ), VMid[ i ], tolerance ),
963  error.str()
964  );
965  }
966 
967  for ( i = nCompt - 1; i >= 0; i-- )
968  {
969  ostringstream error;
970  error << "Back substitution:"
971  << " Pass " << pass
972  << " Cell# " << cell + 1
973  << " V(" << i << ")";
974  ASSERT (
975  isClose< double >( HP.getV( i ), V[ i ], tolerance ),
976  error.str()
977  );
978  }
979  }
980 
981  // cleanup
982  shell->doDelete( n );
983  }
984  cout << "." << flush;
985 
986 // TEST_END;
987 }
988 
989 #endif // DO_UNIT_TESTS
double getVMid(unsigned int row) const
void makeFullMatrix(const vector< TreeNodeStruct > &tree, double dt, vector< vector< double > > &matrix)
#define ASSERT(unused, message)
Definition: HinesMatrix.h:22
static int children(Id compartment, vector< Id > &ret)
Definition: HSolveUtils.cpp:47
char * data() const
Definition: Eref.cpp:41
uint32_t value
Definition: moosemodule.h:42
void walkTree(Id seed)
static int leakageChannels(Id compartment, vector< Id > &ret)
vector< double > VMid_
middle of a time step.
Definition: HinesMatrix.h:83
bool bad() const
Definition: ObjId.cpp:18
vector< unsigned int > children
Hines indices of child compts.
Definition: HinesMatrix.h:47
void setup(Id seed, double dt)
void setup(const vector< TreeNodeStruct > &tree, double dt)
Definition: HinesMatrix.cpp:25
double getB(unsigned int row) const
Definition: ObjId.h:20
static int adjacent(Id compartment, vector< Id > &ret)
Definition: HSolveUtils.cpp:36
Eref eref() const
Definition: Id.cpp:125
vector< Id > compartmentId_
Definition: HSolvePassive.h:37
unsigned int nCompt_
Definition: HinesMatrix.h:70
static bool set(const ObjId &dest, const string &field, A arg)
Definition: SetGet.h:245
Id doCreate(string type, ObjId parent, string name, unsigned int numData, NodePolicy nodePolicy=MooseBlockBalance, unsigned int preferredNode=1)
Definition: Shell.cpp:181
vector< vdIterator > backOperand_
Definition: HinesMatrix.h:86
double injectBasal
Definition: HSolveStruct.h:41
void forwardEliminate()
vector< double > V_
Definition: HSolvePassive.h:38
void backwardSubstitute()
ostream & operator<<(ostream &s, const HinesMatrix &m)
vector< CompartmentStruct > compartment_
Definition: HSolvePassive.h:36
double getV(unsigned int row) const
int stage_
reached. Used in getA.
Definition: HinesMatrix.h:87
map< unsigned int, InjectStruct > inject_
Definition: HSolvePassive.h:45
vector< vdIterator > operand_
Definition: HinesMatrix.h:85
bool isClose(double x, double y, double tol)
vector< TreeNodeStruct > tree_
Definition: HSolvePassive.h:41
double injectVarying
Definition: HSolveStruct.h:40
vector< double > HJCopy_
Definition: HinesMatrix.h:82
vector< double > HS_
Definition: HinesMatrix.h:74
static char name[]
Definition: mfield.cpp:401
ObjId doAddMsg(const string &msgType, ObjId src, const string &srcField, ObjId dest, const string &destField)
Definition: Shell.cpp:269
bool doDelete(ObjId oid)
Definition: Shell.cpp:259
Definition: Id.h:17
static A get(const ObjId &dest, const string &field)
Definition: SetGet.h:284
vector< JunctionStruct > junction_
Definition: HinesMatrix.h:73
vector< double > HJ_
Definition: HinesMatrix.h:79
vector< double >::iterator vdIterator
Definition: HinesMatrix.h:68
double getA(unsigned int row, unsigned int col) const
Definition: Shell.h:43
double dt_
Definition: HinesMatrix.h:71