MOOSE - Multiscale Object Oriented Simulation Environment
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Gsolve.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-2010 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 "../basecode/header.h"
10 #include "../basecode/global.h"
11 
12 #include "../mesh/VoxelJunction.h"
13 
14 #include "VoxelPoolsBase.h"
15 #include "XferInfo.h"
16 #include "ZombiePoolInterface.h"
17 
18 #include "RateTerm.h"
19 #include "FuncTerm.h"
20 #include "FuncRateTerm.h"
21 #include "SparseMatrix.h"
22 #include "KinSparseMatrix.h"
23 #include "GssaSystem.h"
24 #include "Stoich.h"
25 #include "GssaVoxelPools.h"
26 
27 #include <future>
28 #include <atomic>
29 #include <thread>
30 
31 #include "Gsolve.h"
32 
33 #define SIMPLE_ROUNDING 0
34 
35 const unsigned int OFFNODE = ~0;
36 
38 {
40  // Field definitions
42 
43  static ValueFinfo< Gsolve, Id > stoich (
44  "stoich",
45  "Stoichiometry object for handling this reaction system.",
48  );
49 
50  static ValueFinfo< Gsolve, Id > compartment (
51  "compartment",
52  "Compartment that contains this reaction system.",
55  );
56 
57  static ReadOnlyValueFinfo< Gsolve, unsigned int > numLocalVoxels(
58  "numLocalVoxels",
59  "Number of voxels in the core reac-diff system, on the "
60  "current solver. ",
62  );
63  static LookupValueFinfo<
64  Gsolve, unsigned int, vector< double > > nVec(
65  "nVec",
66  "vector of pool counts",
69  );
70  static ValueFinfo< Gsolve, unsigned int > numAllVoxels(
71  "numAllVoxels",
72  "Number of voxels in the entire reac-diff system, "
73  "including proxy voxels to represent abutting compartments.",
76  );
77 
78  static ValueFinfo< Gsolve, unsigned int > numPools(
79  "numPools",
80  "Number of molecular pools in the entire reac-diff system, "
81  "including variable, function and buffered.",
84  );
85 
86  static ValueFinfo< Gsolve, bool > useRandInit(
87  "useRandInit",
88  "Flag: True when using probabilistic (random) rounding.\n "
89  "Default: True.\n "
90  "When initializing the mol# from floating-point Sinit values, "
91  "we have two options. One is to look at each Sinit, and round "
92  "to the nearest integer. The other is to look at each Sinit, "
93  "and probabilistically round up or down depending on the "
94  "value. For example, if we had a Sinit value of 1.49, "
95  "this would always be rounded to 1.0 if the flag is false, "
96  "and would be rounded to 1.0 and 2.0 in the ratio 51:49 if "
97  "the flag is true. ",
100  );
101 
102  static ValueFinfo< Gsolve, bool > useClockedUpdate(
103  "useClockedUpdate",
104  "Flag: True to cause all reaction propensities to be updated "
105  "on every clock tick.\n"
106  "Default: False.\n"
107  "This flag should be set when the reaction system "
108  "includes a function with a dependency on time or on external "
109  "events. It has a significant speed penalty so the flag "
110  "should not be set unless there are such functions. " ,
113  );
115  Gsolve, unsigned int, vector< unsigned int > > numFire(
116  "numFire",
117  "Vector of the number of times each reaction has fired."
118  "Indexed by the voxel number."
119  "Zeroed out at reinit.",
121  );
122 
124  // DestFinfo definitions
126 
127  static DestFinfo process( "process",
128  "Handles process call",
130  static DestFinfo reinit( "reinit",
131  "Handles reinit call",
133 
134  static DestFinfo voxelVol( "voxelVol",
135  "Handles updates to all voxels. Comes from parent "
136  "ChemCompt object.",
137  new OpFunc1< Gsolve, vector< double > >(
139  );
140 
141  static DestFinfo initProc( "initProc",
142  "Handles initProc call from Clock",
144  static DestFinfo initReinit( "initReinit",
145  "Handles initReinit call from Clock",
147 
149  // Shared definitions
151  static Finfo* procShared[] =
152  {
153  &process, &reinit
154  };
155  static SharedFinfo proc( "proc",
156  "Shared message for process and reinit",
157  procShared, sizeof( procShared ) / sizeof( const Finfo* )
158  );
159 
160  static Finfo* initShared[] =
161  {
162  &initProc, &initReinit
163  };
164  static SharedFinfo init( "init",
165  "Shared message for initProc and initReinit. This is used"
166  " when the system has cross-compartment reactions. ",
167  initShared, sizeof( initShared ) / sizeof( const Finfo* )
168  );
169 
171 
172  static Finfo* gsolveFinfos[] =
173  {
174  &stoich, // Value
175  &numLocalVoxels, // ReadOnlyValue
176  &nVec, // LookupValue
177  &numAllVoxels, // ReadOnlyValue
178  &numPools, // Value
179  &voxelVol, // DestFinfo
180  &proc, // SharedFinfo
181  &init, // SharedFinfo
182  // Here we put new fields that were not there in the Ksolve.
183  &useRandInit, // Value
184  &useClockedUpdate, // Value
185  &numFire, // ReadOnlyLookupValue
186  };
187 
188  static Dinfo< Gsolve > dinfo;
189  static Cinfo gsolveCinfo(
190  "Gsolve",
192  gsolveFinfos,
193  sizeof(gsolveFinfos)/sizeof(Finfo *),
194  &dinfo
195  );
196 
197  return &gsolveCinfo;
198 }
199 
201 
203 // Class definitions
205 
207 #if PARALLELIZE_GSOLVE_WITH_CPP11_ASYNC
208  numThreads_ ( 2 ),
209 #endif
210  pools_( 1 ),
211  startVoxel_( 0 ),
212  dsolve_(),
213  dsolvePtr_( 0 ),
214  useClockedUpdate_( false )
215 {
216  ;
217 }
218 
220 {
221  return *this;
222 }
223 
225 {
226  ;
227 }
228 
230 // Field Access functions
232 
234 {
235  return stoich_;
236 }
237 
239 {
240  if ( ( compt.element()->cinfo()->isA( "ChemCompt" ) ) )
241  {
242  compartment_ = compt;
243  vector< double > vols =
244  Field< vector< double > >::get( compt, "voxelVolume" );
245  if ( vols.size() > 0 )
246  {
247  pools_.resize( vols.size() );
248  for ( unsigned int i = 0; i < vols.size(); ++i )
249  {
250  pools_[i].setVolume( vols[i] );
251  }
252  }
253  }
254 }
255 
257 {
258  return compartment_;
259 }
260 
261 void Gsolve::setStoich( Id stoich )
262 {
263  // This call is done _before_ setting the path on stoich
264  assert( stoich.element()->cinfo()->isA( "Stoich" ) );
265  stoich_ = stoich;
266  stoichPtr_ = reinterpret_cast< Stoich* >( stoich.eref().data() );
267  if ( stoichPtr_->getNumAllPools() == 0 )
268  {
269  stoichPtr_ = 0;
270  return;
271  }
273  sys_.isReady = false;
274  for ( unsigned int i = 0; i < pools_.size(); ++i )
276 }
277 
278 unsigned int Gsolve::getNumLocalVoxels() const
279 {
280  return pools_.size();
281 }
282 
283 unsigned int Gsolve::getNumAllVoxels() const
284 {
285  return pools_.size(); // Need to redo.
286 }
287 
288 // If we're going to do this, should be done before the zombification.
289 void Gsolve::setNumAllVoxels( unsigned int numVoxels )
290 {
291  if ( numVoxels == 0 )
292  {
293  return;
294  }
295  pools_.resize( numVoxels );
296  sys_.isReady = false;
297 }
298 
299 vector< double > Gsolve::getNvec( unsigned int voxel) const
300 {
301  static vector< double > dummy;
302  if ( voxel < pools_.size() )
303  {
304  return const_cast< GssaVoxelPools* >( &( pools_[ voxel ]) )->Svec();
305  }
306  return dummy;
307 }
308 
309 void Gsolve::setNvec( unsigned int voxel, vector< double > nVec )
310 {
311  if ( voxel < pools_.size() )
312  {
313  if ( nVec.size() != pools_[voxel].size() )
314  {
315  cout << "Warning: Gsolve::setNvec: size mismatch ( " <<
316  nVec.size() << ", " << pools_[voxel].size() << ")\n";
317  return;
318  }
319  double* s = pools_[voxel].varS();
320  for ( unsigned int i = 0; i < nVec.size(); ++i )
321  {
322  s[i] = round( nVec[i] );
323  if ( s[i] < 0.0 )
324  s[i] = 0.0;
325  }
326  if ( sys_.isReady )
327  pools_[voxel].refreshAtot( &sys_ );
328  }
329 }
330 
331 vector< unsigned int > Gsolve::getNumFire( unsigned int voxel) const
332 {
333  static vector< unsigned int > dummy;
334  if ( voxel < pools_.size() )
335  {
336  return const_cast< GssaVoxelPools* >( &( pools_[ voxel ]) )->numFire();
337  }
338  return dummy;
339 }
340 
341 
343 {
344  return sys_.useRandInit;
345 }
346 
347 void Gsolve::setRandInit( bool val )
348 {
349  sys_.useRandInit = val;
350 }
351 
353 {
354  return useClockedUpdate_;
355 }
356 
357 void Gsolve::setClockedUpdate( bool val )
358 {
359  useClockedUpdate_ = val;
360 }
361 
362 
363 #if PARALLELIZE_GSOLVE_WITH_CPP11_ASYNC
364 
371 void Gsolve::parallel_advance(int begin, int end, size_t nWorkers, const ProcPtr p
372  , const GssaSystem* sys
373  )
374 {
375  std::atomic<int> idx( begin );
376  for (size_t cpu = 0; cpu != nWorkers; ++cpu)
377  {
378  std::async( std::launch::async,
379  [this, &idx, end, p, sys]()
380  {
381  for (;;)
382  {
383  int i = idx++;
384  if (i >= end)
385  break;
386  pools_[i].advance( p, sys);
387  }
388  }
389  );
390  }
391 }
392 
393 #endif
394 
396 // Process operations.
398 void Gsolve::process( const Eref& e, ProcPtr p )
399 {
400  // cout << stoichPtr_ << " dsolve = " << dsolvePtr_ << endl;
401  if ( !stoichPtr_ )
402  return;
403 
404  // First, handle incoming diffusion values. Note potential for
405  // issues with roundoff if diffusion is not integral.
406  if ( dsolvePtr_ )
407  {
408  vector< double > dvalues( 4 );
409  dvalues[0] = 0;
410  dvalues[1] = getNumLocalVoxels();
411  dvalues[2] = 0;
412  dvalues[3] = stoichPtr_->getNumVarPools();
413  dsolvePtr_->getBlock( dvalues );
414  dsolvePtr_->setPrev();
415 
416  // Here we need to convert to integers, just in case. Normally
417  // one would use a stochastic (integral) diffusion method with
418  // the GSSA, but in mixed models it may be more complicated.
419  vector< double >::iterator i = dvalues.begin() + 4;
420 
421  for ( ; i != dvalues.end(); ++i )
422  {
423  // cout << *i << " " << round( *i ) << " ";
424 #if SIMPLE_ROUNDING
425  *i = round( *i );
426 #else
427  double base = floor( *i );
428 
429  // Use global RNG.
430  if ( moose::mtrand() >= (*i - base) )
431  *i = base;
432  else
433  *i = base + 1.0;
434 #endif
435  }
436  setBlock( dvalues );
437  }
438 
439  // Third: Fix the rates if we have had any diffusion or xreacs
440  // happening. This is very inefficient at this point, need to fix.
441  if ( dsolvePtr_ )
442  {
443  for ( vector< GssaVoxelPools >::iterator
444  i = pools_.begin(); i != pools_.end(); ++i )
445  {
446  i->refreshAtot( &sys_ );
447  }
448  }
449  // Fourth, update the mol #s.
450  // First we advance the simulation.
451  size_t nvPools = pools_.size( );
452 
453 #if PARALLELIZE_GSOLVE_WITH_CPP11_ASYNC
454  // If there is only one voxel-pool or one thread is specified by user then
455  // there is no point in using std::async there.
456  if( 1 == getNumThreads( ) || 1 == nvPools )
457  {
458  for ( size_t i = 0; i < nvPools; i++ )
459  pools_[i].advance( p, &sys_ );
460  }
461  else
462  {
463  /*-----------------------------------------------------------------------------
464  * Somewhat complicated computation to compute the number of threads. 1
465  * thread per (at least) voxel pool is ideal situation.
466  *-----------------------------------------------------------------------------*/
467  size_t grainSize = min( nvPools, 1 + (nvPools / numThreads_ ) );
468  size_t nWorkers = nvPools / grainSize;
469 
470  for (size_t i = 0; i < nWorkers; i++)
471  parallel_advance( i * grainSize, (i+1) * grainSize, nWorkers, p, &sys_ );
472 
473  }
474 #else
475  for ( size_t i = 0; i < nvPools; i++ )
476  pools_[i].advance( p, &sys_ );
477 #endif
478 
479  if ( useClockedUpdate_ ) // Check if a clocked stim is to be updated
480  {
481  for ( auto &v : pools_ )
482  v.recalcTime( &sys_, p->currTime );
483  }
484 
485  // Finally, assemble and send the integrated values off for the Dsolve.
486  if ( dsolvePtr_ )
487  {
488  vector< double > kvalues( 4 );
489  kvalues[0] = 0;
490  kvalues[1] = getNumLocalVoxels();
491  kvalues[2] = 0;
492  kvalues[3] = stoichPtr_->getNumVarPools();
493  getBlock( kvalues );
494  dsolvePtr_->setBlock( kvalues );
495 
496  // Now use the values in the Dsolve to update junction fluxes
497  // for diffusion, channels, and xreacs
499  // Here the Gsolve may need to do something to convert to integers
500  }
501 }
502 
503 void Gsolve::reinit( const Eref& e, ProcPtr p )
504 {
505  if ( !stoichPtr_ )
506  return;
507  if ( !sys_.isReady )
509  // First reinit concs.
510  for ( vector< GssaVoxelPools >::iterator
511  i = pools_.begin(); i != pools_.end(); ++i )
512  {
513  i->reinit( &sys_ );
514  }
515  // Second, update the atots.
516  for ( vector< GssaVoxelPools >::iterator
517  i = pools_.begin(); i != pools_.end(); ++i )
518  {
519  i->refreshAtot( &sys_ );
520  }
521 
522 #if PARALLELIZE_GSOLVE_WITH_CPP11_ASYNC
523  if( 1 < getNumThreads( ) )
524  cout << "Info: Using threaded gsolve: " << getNumThreads( )
525  << " threads. " << endl;
526 #endif
527 }
528 
530 // init operations.
532 void Gsolve::initProc( const Eref& e, ProcPtr p )
533 {;}
534 
535 void Gsolve::initReinit( const Eref& e, ProcPtr p )
536 {
537  if ( !stoichPtr_ )
538  return;
539  for ( unsigned int i = 0 ; i < pools_.size(); ++i )
540  {
541  pools_[i].reinit( &sys_ );
542  }
543 }
545 // Solver setup
547 
549 {
554  vector< vector< unsigned int > > & dep = sys_.dependency;
555  dep.resize( stoichPtr_->getNumRates() );
556  for ( unsigned int i = 0; i < stoichPtr_->getNumRates(); ++i )
557  {
559  }
560  fillMmEnzDep();
561  fillPoolFuncDep();
564  for ( vector< GssaVoxelPools >::iterator
565  i = pools_.begin(); i != pools_.end(); ++i )
566  {
567  i->setNumReac( stoichPtr_->getNumRates() );
568  i->updateAllRateTerms( stoichPtr_->getRateTerms(),
570  }
571  sys_.isReady = true;
572 }
573 
581 {
582  unsigned int numRates = stoichPtr_->getNumRates();
583  vector< unsigned int > indices;
584 
585  // Make a map to look up enzyme RateTerm using
586  // the key of the enzyme molecule.
587  map< unsigned int, unsigned int > enzMolMap;
588  for ( unsigned int i = 0; i < numRates; ++i )
589  {
590  const MMEnzymeBase* mme = dynamic_cast< const MMEnzymeBase* >(
591  stoichPtr_->rates( i ) );
592  if ( mme )
593  {
594  vector< unsigned int > reactants;
595  mme->getReactants( reactants );
596  if ( reactants.size() > 1 )
597  enzMolMap[ reactants.front() ] = i; // front is enzyme.
598  }
599  }
600 
601  // Use the map to fill in deps.
602  for ( unsigned int i = 0; i < numRates; ++i )
603  {
604  // Extract the row of all molecules that depend on the reac.
605  const int* entry;
606  const unsigned int* colIndex;
607 
608  unsigned int numInRow =
609  sys_.transposeN.getRow( i, &entry, &colIndex );
610  for( unsigned int j = 0; j < numInRow; ++j )
611  {
612  map< unsigned int, unsigned int >::iterator pos =
613  enzMolMap.find( colIndex[j] );
614  if ( pos != enzMolMap.end() )
615  sys_.dependency[i].push_back( pos->second );
616  }
617  }
618 }
619 
632 {
633  // create map of funcs that depend on specified molecule.
634  vector< vector< unsigned int > > funcMap(
636  unsigned int numFuncs = stoichPtr_->getNumFuncs();
637  for ( unsigned int i = 0; i < numFuncs; ++i )
638  {
639  const FuncTerm *f = stoichPtr_->funcs( i );
640  vector< unsigned int > molIndex = f->getReactantIndex();
641  for ( unsigned int j = 0; j < molIndex.size(); ++j )
642  funcMap[ molIndex[j] ].push_back( i );
643  }
644  // The output of each func is a mol indexed as
645  // numVarMols + numBufMols + i
646  unsigned int numRates = stoichPtr_->getNumRates();
647  sys_.dependentMathExpn.resize( numRates );
648  vector< unsigned int > indices;
649  for ( unsigned int i = 0; i < numRates; ++i )
650  {
651  vector< unsigned int >& dep = sys_.dependentMathExpn[ i ];
652  dep.resize( 0 );
653  // Extract the row of all molecules that depend on the reac.
654  const int* entry;
655  const unsigned int* colIndex;
656  unsigned int numInRow =
657  sys_.transposeN.getRow( i, &entry, &colIndex );
658  for ( unsigned int j = 0; j < numInRow; ++j )
659  {
660  unsigned int molIndex = colIndex[j];
661  vector< unsigned int >& funcs = funcMap[ molIndex ];
662  dep.insert( dep.end(), funcs.begin(), funcs.end() );
663  for ( unsigned int k = 0; k < funcs.size(); ++k )
664  {
665  // unsigned int outputMol = funcs[k] + funcOffset;
666  unsigned int outputMol = stoichPtr_->funcs( funcs[k] )->getTarget();
667  // Insert reac deps here. Columns are reactions.
668  vector< int > e; // Entries: we don't need.
669  vector< unsigned int > c; // Column index: the reactions.
671  getRow( outputMol, e, c );
672  // Each of the reacs (col entries) depend on this func.
673  vector< unsigned int > rdep = sys_.dependency[i];
674  rdep.insert( rdep.end(), c.begin(), c.end() );
675  }
676  }
677  }
678 }
679 
695 {
696  // create map of funcs that depend on specified molecule.
697  vector< vector< unsigned int > > funcMap(
699  const vector< RateTerm* >& rates = stoichPtr_->getRateTerms();
700  vector< FuncRate* > incrementRates;
701  vector< unsigned int > incrementRateIndex;
702  const vector< RateTerm* >::const_iterator q;
703  for ( unsigned int i = 0; i < rates.size(); ++i )
704  {
705  FuncRate *term =
706  dynamic_cast< FuncRate* >( rates[i] );
707  if (term)
708  {
709  incrementRates.push_back( term );
710  incrementRateIndex.push_back( i );
711  }
712  }
713 
714  for ( unsigned int k = 0; k < incrementRates.size(); ++k )
715  {
716  const vector< unsigned int >& molIndex =
717  incrementRates[k]->getFuncArgIndex();
718  for ( unsigned int j = 0; j < molIndex.size(); ++j )
719  funcMap[ molIndex[j] ].push_back( incrementRateIndex[k] );
720  }
721 
722  unsigned int numRates = stoichPtr_->getNumRates();
723  sys_.dependentMathExpn.resize( numRates );
724  vector< unsigned int > indices;
725  for ( unsigned int i = 0; i < numRates; ++i )
726  {
727  // Algorithm:
728  // 1.Go through stoich matrix finding all the poolIndices affected
729  // by each Rate Term.
730  // 2.Use funcMap to look up FuncRateTerms affected by these indices
731  // 3. Add the rateTerm->FuncRateTerm mapping to the dependencies.
732 
733  const int* entry;
734  const unsigned int* colIndex;
735  unsigned int numInRow =
736  sys_.transposeN.getRow( i, &entry, &colIndex );
737  // 1.Go through stoich matrix finding all the poolIndices affected
738  // by each Rate Term.
739  for ( unsigned int j = 0; j < numInRow; ++j )
740  {
741  unsigned int molIndex = colIndex[j]; // Affected poolIndex
742 
743  // 2.Use funcMap to look up FuncRateTerms affected by these indices
744  vector< unsigned int >& funcs = funcMap[ molIndex ];
745  // 3. Add the rateTerm->FuncRateTerm mapping to the dependencies.
746  vector< unsigned int >& rdep = sys_.dependency[i];
747  rdep.insert( rdep.end(), funcs.begin(), funcs.end() );
748  }
749  }
750 }
751 
752 /*
753 void Gsolve::fillMathDep()
754 {
755  // create map of funcs that depend on specified molecule.
756  vector< vector< unsigned int > > funcMap(
757  stoichPtr_->getNumAllPools() );
758  unsigned int numFuncs = stoichPtr_->getNumFuncs();
759  for ( unsigned int i = 0; i < numFuncs; ++i ) {
760  const FuncTerm *f = stoichPtr_->funcs( i );
761  vector< unsigned int > molIndex = f->getReactantIndex();
762  for ( unsigned int j = 0; j < molIndex.size(); ++j )
763  funcMap[ molIndex[j] ].push_back( i );
764  }
765  // The output of each func is a mol indexed as
766  // numVarMols + numBufMols + i
767  unsigned int funcOffset =
768  stoichPtr_->getNumVarPools() + stoichPtr_->getNumProxyPools() + stoichPtr_->getNumBufPools();
769  unsigned int numRates = stoichPtr_->getNumRates();
770  sys_.dependentMathExpn.resize( numRates );
771  vector< unsigned int > indices;
772  for ( unsigned int i = 0; i < numRates; ++i ) {
773  vector< unsigned int >& dep = sys_.dependentMathExpn[ i ];
774  dep.resize( 0 );
775  // Extract the row of all molecules that depend on the reac.
776  const int* entry;
777  const unsigned int* colIndex;
778  unsigned int numInRow =
779  sys_.transposeN.getRow( i, &entry, &colIndex );
780  for ( unsigned int j = 0; j < numInRow; ++j ) {
781  unsigned int molIndex = colIndex[j];
782  vector< unsigned int >& funcs = funcMap[ molIndex ];
783  dep.insert( dep.end(), funcs.begin(), funcs.end() );
784  for ( unsigned int k = 0; k < funcs.size(); ++k ) {
785  unsigned int outputMol = funcs[k] + funcOffset;
786  // Insert reac deps here. Columns are reactions.
787  vector< int > e; // Entries: we don't need.
788  vector< unsigned int > c; // Column index: the reactions.
789  stoichPtr_->getStoichiometryMatrix().
790  getRow( outputMol, e, c );
791  // Each of the reacs (col entries) depend on this func.
792  vector< unsigned int > rdep = sys_.dependency[i];
793  rdep.insert( rdep.end(), c.begin(), c.end() );
794  }
795  }
796  }
797 }
798 */
799 
805 void Gsolve::insertMathDepReacs( unsigned int mathDepIndex,
806  unsigned int firedReac )
807 {
808  /*
809  unsigned int molIndex = sumTotals_[ mathDepIndex ].target( S_ );
810  vector< unsigned int > reacIndices;
811 
812  // Extract the row of all reacs that depend on the target molecule
813  if ( N_.getRowIndices( molIndex, reacIndices ) > 0 ) {
814  vector< unsigned int >& dep = dependency_[ firedReac ];
815  dep.insert( dep.end(), reacIndices.begin(), reacIndices.end() );
816  }
817  */
818 }
819 
820 // Clean up dependency lists: Ensure only unique entries.
821 // Also a reac cannot depend on itself.
823 {
824  unsigned int numRates = stoichPtr_->getNumRates();
825  for ( unsigned int i = 0; i < numRates; ++i )
826  {
827  vector< unsigned int >& dep = sys_.dependency[ i ];
828  // Here we want to remove self-entries as well as duplicates.
829  sort( dep.begin(), dep.end() );
830  vector< unsigned int >::iterator k = dep.begin();
831 
833  vector< unsigned int >::iterator pos =
834  unique( dep.begin(), dep.end() );
835  dep.resize( pos - dep.begin() );
836  /*
837  */
838  }
839 }
840 
842 // Solver ops
844 unsigned int Gsolve::getPoolIndex( const Eref& e ) const
845 {
846  return stoichPtr_->convertIdToPoolIndex( e.id() );
847 }
848 
849 unsigned int Gsolve::getVoxelIndex( const Eref& e ) const
850 {
851  unsigned int ret = e.dataIndex();
852  if ( ret < startVoxel_ || ret >= startVoxel_ + pools_.size() )
853  return OFFNODE;
854  return ret - startVoxel_;
855 }
856 
857 void Gsolve::setDsolve( Id dsolve )
858 {
859  if ( dsolve == Id () )
860  {
861  dsolvePtr_ = 0;
862  dsolve_ = Id();
863  }
864  else if ( dsolve.element()->cinfo()->isA( "Dsolve" ) )
865  {
866  dsolve_ = dsolve;
867  dsolvePtr_ = reinterpret_cast< ZombiePoolInterface* >(
868  dsolve.eref().data() );
869  }
870  else
871  {
872  cout << "Warning: Gsolve::setDsolve: Object '" << dsolve.path() <<
873  "' should be class Dsolve, is: " <<
874  dsolve.element()->cinfo()->name() << endl;
875  }
876 }
877 
878 
880 // Zombie Pool Access functions
882 
883 void Gsolve::setN( const Eref& e, double v )
884 {
885  unsigned int vox = getVoxelIndex( e );
886  if ( vox != OFFNODE )
887  {
888  if ( e.element()->cinfo()->isA( "ZombieBufPool" ) )
889  {
890  // Do NOT round it here, it is folded into rate term.
891  pools_[vox].setN( getPoolIndex( e ), v );
892  // refresh rates because nInit controls ongoing value of n.
893  if ( sys_.isReady )
894  pools_[vox].refreshAtot( &sys_ );
895  }
896  else
897  {
898  pools_[vox].setN( getPoolIndex( e ), round( v ) );
899  }
900  }
901 }
902 
903 double Gsolve::getN( const Eref& e ) const
904 {
905  unsigned int vox = getVoxelIndex( e );
906  if ( vox != OFFNODE )
907  return pools_[vox].getN( getPoolIndex( e ) );
908  return 0.0;
909 }
910 
911 void Gsolve::setNinit( const Eref& e, double v )
912 {
913  unsigned int vox = getVoxelIndex( e );
914  if ( vox != OFFNODE )
915  {
916  if ( e.element()->cinfo()->isA( "ZombieBufPool" ) )
917  {
918  // Do NOT round it here, it is folded into rate term.
919  pools_[vox].setNinit( getPoolIndex( e ), v );
920  // refresh rates because nInit controls ongoing value of n.
921  if ( sys_.isReady )
922  pools_[vox].refreshAtot( &sys_ );
923  }
924  else
925  {
926  // I now do the rounding at reinit time. It is better there as
927  // it can give a distinct value each cycle. It is also better
928  // to keep the full resolution of Ninit for volume scaling.
929  // pools_[vox].setNinit( getPoolIndex( e ), round( v ) );
930  pools_[vox].setNinit( getPoolIndex( e ), v );
931  }
932  }
933 }
934 
935 double Gsolve::getNinit( const Eref& e ) const
936 {
937  unsigned int vox = getVoxelIndex( e );
938  if ( vox != OFFNODE )
939  return pools_[vox].getNinit( getPoolIndex( e ) );
940  return 0.0;
941 }
942 
943 void Gsolve::setDiffConst( const Eref& e, double v )
944 {
945  ; // Do nothing.
946 }
947 
948 double Gsolve::getDiffConst( const Eref& e ) const
949 {
950  return 0;
951 }
952 
953 void Gsolve::setNumPools( unsigned int numPoolSpecies )
954 {
955  sys_.isReady = false;
956  unsigned int numVoxels = pools_.size();
957  for ( unsigned int i = 0 ; i < numVoxels; ++i )
958  {
959  pools_[i].resizeArrays( numPoolSpecies );
960  }
961 }
962 
963 unsigned int Gsolve::getNumPools() const
964 {
965  if ( pools_.size() > 0 )
966  return pools_[0].size();
967  return 0;
968 }
969 
970 void Gsolve::getBlock( vector< double >& values ) const
971 {
972  unsigned int startVoxel = values[0];
973  unsigned int numVoxels = values[1];
974  unsigned int startPool = values[2];
975  unsigned int numPools = values[3];
976 
977  assert( startVoxel >= startVoxel_ );
978  assert( numVoxels <= pools_.size() );
979  assert( pools_.size() > 0 );
980  assert( numPools + startPool <= pools_[0].size() );
981  values.resize( 4 + numVoxels * numPools );
982 
983  for ( unsigned int i = 0; i < numVoxels; ++i )
984  {
985  const double* v = pools_[ startVoxel + i ].S();
986  for ( unsigned int j = 0; j < numPools; ++j )
987  {
988  values[ 4 + j * numVoxels + i] = v[ j + startPool ];
989  }
990  }
991 }
992 
993 void Gsolve::setBlock( const vector< double >& values )
994 {
995  unsigned int startVoxel = values[0];
996  unsigned int numVoxels = values[1];
997  unsigned int startPool = values[2];
998  unsigned int numPools = values[3];
999 
1000  assert( startVoxel >= startVoxel_ );
1001  assert( numVoxels <= pools_.size() );
1002  assert( pools_.size() > 0 );
1003  assert( numPools + startPool <= pools_[0].size() );
1004 
1005  for ( unsigned int i = 0; i < numVoxels; ++i )
1006  {
1007  double* v = pools_[ startVoxel + i ].varS();
1008  for ( unsigned int j = 0; j < numPools; ++j )
1009  {
1010  v[ j + startPool ] = values[ 4 + j * numVoxels + i ];
1011  }
1012  }
1013 }
1014 
1016 void Gsolve::updateVoxelVol( vector< double > vols )
1017 {
1018  // For now we assume identical numbers of voxels. Also assume
1019  // identical voxel junctions. But it should not be too hard to
1020  // update those too.
1021  if ( vols.size() == pools_.size() )
1022  {
1023  for ( unsigned int i = 0; i < vols.size(); ++i )
1024  {
1025  pools_[i].setVolumeAndDependencies( vols[i] );
1026  }
1027  updateRateTerms( ~0U );
1028  }
1029 }
1030 
1031 void Gsolve::updateRateTerms( unsigned int index )
1032 {
1033  if ( index == ~0U )
1034  {
1035  // unsigned int numCrossRates = stoichPtr_->getNumRates() - stoichPtr_->getNumCoreRates();
1036  for ( unsigned int i = 0 ; i < pools_.size(); ++i )
1037  {
1038  pools_[i].updateAllRateTerms( stoichPtr_->getRateTerms(),
1040  }
1041  }
1042  else if ( index < stoichPtr_->getNumRates() )
1043  {
1044  for ( unsigned int i = 0 ; i < pools_.size(); ++i )
1046  stoichPtr_->getNumCoreRates(), index );
1047  }
1048 }
1049 
1051 
1052 VoxelPoolsBase* Gsolve::pools( unsigned int i )
1053 {
1054  if ( pools_.size() > i )
1055  return &pools_[i];
1056  return 0;
1057 }
1058 
1059 double Gsolve::volume( unsigned int i ) const
1060 {
1061  if ( pools_.size() > i )
1062  return pools_[i].getVolume();
1063  return 0.0;
1064 }
1065 
1066 #if PARALLELIZE_GSOLVE_WITH_CPP11_ASYNC
1067 unsigned int Gsolve::getNumThreads( ) const
1068 {
1069  return numThreads_;
1070 }
1071 
1072 void Gsolve::setNumThreads( unsigned int x )
1073 {
1074  numThreads_ = x;
1075 }
1076 #endif
unsigned int getNumAllVoxels() const
Definition: Gsolve.cpp:283
Id id() const
Definition: Eref.cpp:62
void fillIncrementFuncDep()
Definition: Gsolve.cpp:694
Id init(int argc, char **argv, bool &doUnitTests, bool &doRegressionTests, unsigned int &benchmark)
Definition: main.cpp:150
bool getRandInit() const
Flag: returns true if randomized round to integers is done.
Definition: Gsolve.cpp:342
double getN(const Eref &e) const
Get # of molecules in given pool and voxel. Varies with time.
Definition: Gsolve.cpp:903
char * data() const
Definition: Eref.cpp:41
Id getCompartment() const
Inherited from ZombiePoolInterface.
Definition: Gsolve.cpp:256
void updateVoxelVol(vector< double > vols)
Definition: Gsolve.cpp:1016
virtual unsigned int getReactants(vector< unsigned int > &molIndex) const =0
Gsolve & operator=(const Gsolve &)
Definition: Gsolve.cpp:219
const unsigned int getTarget() const
Definition: FuncTerm.cpp:105
Element * element() const
Synonym for Id::operator()()
Definition: Id.cpp:113
unsigned int getVoxelIndex(const Eref &e) const
Definition: Gsolve.cpp:849
vector< vector< unsigned int > > dependency
Definition: GssaSystem.h:25
double currTime
Definition: ProcInfo.h:19
std::string path(const std::string &separator="/") const
Definition: Id.cpp:76
void process(const Eref &e, ProcPtr p)
Definition: Gsolve.cpp:398
Definition: Dinfo.h:60
unsigned int getRow(unsigned int row, const T **entry, const unsigned int **colIndex) const
Definition: SparseMatrix.h:288
Definition: SetGet.h:236
static DestFinfo dummy("dummy","This Finfo is a dummy. If you are reading this you have used an invalid index", 0)
void setStoich(Id stoich)
Definition: Gsolve.cpp:261
void setRandInit(bool val)
Flag: set true if randomized round to integers is to be done.
Definition: Gsolve.cpp:347
static const Cinfo * initCinfo()
Definition: Gsolve.cpp:37
const unsigned int OFFNODE
Definition: Gsolve.cpp:35
void setNvec(unsigned int voxel, vector< double > vec)
Definition: Gsolve.cpp:309
unsigned int startVoxel_
First voxel indexed on the current node.
Definition: Gsolve.h:157
unsigned int dataIndex() const
Definition: Eref.h:50
unsigned int getPoolIndex(const Eref &e) const
Return pool index, using Stoich ptr to do lookup.
Definition: Gsolve.cpp:844
void fillPoolFuncDep()
Definition: Gsolve.cpp:631
void fillMmEnzDep()
Definition: Gsolve.cpp:580
const KinSparseMatrix & getStoichiometryMatrix() const
Updates the rates for cross-compartment reactions.
Definition: Stoich.cpp:1221
Stoich * stoichPtr_
Utility ptr used to help Pool Id lookups by the Ksolve.
Definition: Gsolve.h:160
void initReinit(const Eref &e, ProcPtr p)
Definition: Gsolve.cpp:535
Eref eref() const
Definition: Id.cpp:125
void transpose()
Definition: SparseMatrix.h:456
virtual void updateJunctions(double dt)
Used for telling Dsolver to handle all ops across Junctions.
Element * element() const
Definition: Eref.h:42
vector< vector< unsigned int > > dependentMathExpn
Definition: GssaSystem.h:26
double getDiffConst(const Eref &e) const
Diffusion constant: Only one per pool, voxel number is ignored.
Definition: Gsolve.cpp:948
static const Cinfo * gsolveCinfo
Definition: Gsolve.cpp:200
Stoich * stoich
Definition: GssaSystem.h:31
void setN(const Eref &e, double v)
Set # of molecules in given pool and voxel. Varies with time.
Definition: Gsolve.cpp:883
void updateRateTerms(unsigned int index)
Definition: Gsolve.cpp:1031
void rebuildGssaSystem()
Definition: Gsolve.cpp:548
void advance(vector< double > &y, const vector< Triplet< double > > &ops, const vector< double > &diagVal)
Definition: Stoich.h:49
void setClockedUpdate(bool val)
Flag: set true if randomized round to integers is to be done.
Definition: Gsolve.cpp:357
double getNinit(const Eref &e) const
get initial # of molecules in given pool and voxel. Bdry cond.
Definition: Gsolve.cpp:935
unsigned int getNumPools() const
Inherited.
Definition: Gsolve.cpp:963
vector< double > & Svec()
Returns a handle to the mol # vector.
void getGillespieDependence(unsigned int row, vector< unsigned int > &cols) const
const std::string & name() const
Definition: Cinfo.cpp:260
Id getStoich() const
Definition: Gsolve.cpp:233
unsigned int convertIdToPoolIndex(Id id) const
Definition: Stoich.cpp:1464
Gsolve()
Definition: Gsolve.cpp:206
VoxelPoolsBase * pools(unsigned int i)
Inherited.
Definition: Gsolve.cpp:1052
vector< GssaVoxelPools > pools_
Definition: Gsolve.h:154
unsigned int getNumLocalVoxels() const
Number of voxels here. pools_.size() == getNumLocalVoxels.
Definition: Gsolve.cpp:278
double dt
Definition: ProcInfo.h:18
unsigned int getNumFuncs() const
Definition: Stoich.cpp:594
KinSparseMatrix transposeN
Transpose of stoichiometry matrix.
Definition: GssaSystem.h:30
~Gsolve()
Definition: Gsolve.cpp:224
const FuncTerm * funcs(unsigned int i) const
Definition: Stoich.cpp:599
void getBlock(vector< double > &values) const
Definition: Gsolve.cpp:970
void setCompartment(Id compt)
Assigns compartment.
Definition: Gsolve.cpp:238
void insertMathDepReacs(unsigned int mathDepIndex, unsigned int firedReac)
Definition: Gsolve.cpp:805
Definition: OpFunc.h:27
Definition: Eref.h:26
bool isA(const string &ancestor) const
Definition: Cinfo.cpp:280
bool useClockedUpdate_
Flag: True if atot should be updated every clock tick.
Definition: Gsolve.h:171
void setDsolve(Id dsolve)
Definition: Gsolve.cpp:857
virtual void setPrev()
Used to tell Dsolver to assign 'prev' values.
const Cinfo * cinfo() const
Definition: Element.cpp:66
void truncateRow(unsigned int maxColumnIndex)
unsigned int getNumRates() const
Definition: Stoich.cpp:568
unsigned int getNumVarPools() const
Returns number of local pools that are updated by solver.
Definition: Stoich.cpp:510
vector< unsigned int > numFire() const
void setBlock(const vector< double > &values)
Definition: Gsolve.cpp:993
bool getClockedUpdate() const
Flag: returns true if randomized round to integers is done.
Definition: Gsolve.cpp:352
ZombiePoolInterface * dsolvePtr_
Pointer to diffusion solver.
Definition: Gsolve.h:168
const vector< unsigned int > & getReactantIndex() const
Definition: FuncTerm.cpp:67
void setDiffConst(const Eref &e, double v)
Diffusion constant: Only one per pool, voxel number is ignored.
Definition: Gsolve.cpp:943
virtual void setBlock(const vector< double > &values)=0
void convertRatesToStochasticForm()
Definition: Stoich.cpp:1196
const RateTerm * rates(unsigned int i) const
Utility function to return a rates_ entry.
Definition: Stoich.cpp:583
Id compartment_
Id of Chem compartment used to figure out volumes of voxels.
void initProc(const Eref &e, ProcPtr p)
Definition: Gsolve.cpp:532
vector< unsigned int > getNumFire(unsigned int voxel) const
Definition: Gsolve.cpp:331
double mtrand(void)
Generate a random double between 0 and 1.
Definition: global.cpp:97
Definition: Id.h:17
void setNinit(const Eref &e, double v)
Set initial # of molecules in given pool and voxel. Bdry cond.
Definition: Gsolve.cpp:911
unsigned int getNumCoreRates() const
Number of rate terms for reactions purely on this compartment.
Definition: Stoich.cpp:574
Id dsolve_
Definition: Gsolve.h:165
unsigned int getNumAllPools() const
Definition: Stoich.cpp:520
const vector< RateTerm * > & getRateTerms() const
Returns a reference to the entire rates_ vector.
Definition: Stoich.cpp:589
static const Cinfo * initCinfo()
Definition: Neutral.cpp:16
void makeReacDepsUnique()
Definition: Gsolve.cpp:822
GssaSystem sys_
Definition: Gsolve.h:146
void setNumAllVoxels(unsigned int num)
Definition: Gsolve.cpp:289
bool isReady
Definition: GssaSystem.h:49
unsigned int getNumProxyPools() const
Definition: Stoich.cpp:525
vector< double > getNvec(unsigned int voxel) const
Returns the vector of pool Num at the specified voxel.
Definition: Gsolve.cpp:299
void parallel_advance(int begin, int end, size_t nWorkers, ProcPtr p, const GssaSystem *sys)
double volume(unsigned int i) const
Inherited.
Definition: Gsolve.cpp:1059
Definition: Cinfo.h:18
void reinit(const Eref &e, ProcPtr p)
Definition: Gsolve.cpp:503
virtual void getBlock(vector< double > &values) const =0
bool useRandInit
Definition: GssaSystem.h:44
void setNumPools(unsigned int num)
Definition: Gsolve.cpp:953
Definition: Finfo.h:12
Definition: Gsolve.h:14