MOOSE - Multiscale Object Oriented Simulation Environment
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Neuron.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-2014 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 "ElementValueFinfo.h"
13 #include "shell/Shell.h"
14 #include "shell/Wildcard.h"
15 #include "ReadCell.h"
16 #include "utility/Vec.h"
17 #include "SwcSegment.h"
18 #include "Spine.h"
19 #include "Neuron.h"
20 #include "basecode/global.h"
21 
22 #include "muParser.h"
23 
24 class nuParser: public mu::Parser
25 {
26 public:
27  nuParser( const string& expr ):
28  mu::Parser(),
29  p(0.0), // geometrical path distance wound through dendrite
30  g(0.0), // geometrical path distance direct from soma.
31  L(0.0), // electrical distance arg
32  len(0.0), // Length of compt in metres
33  dia(0.0), // Diameter of compt in metres
34  maxP(0.0), // Maximum value of *p* for this neuron.
35  maxG(0.0), // Maximum value of *g* for this neuron.
36  maxL(0.0), // Maximum value of *L* for this neuron.
37  x(0.0), // X position of segment.
38  y(0.0), // Y position of segment.
39  z(0.0), // Z position of segment.
40  oldVal(0.0), // Original value of field, if needed.
41  useOldVal( false ) // is the 'orig' field needed?
42  {
43  DefineVar( "p", &p );
44  DefineVar( "g", &g );
45  DefineVar( "L", &L );
46  DefineVar( "len", &len );
47  DefineVar( "dia", &dia );
48  DefineVar( "maxP", &maxP );
49  DefineVar( "maxG", &maxG );
50  DefineVar( "maxL", &maxL );
51  DefineVar( "x", &x );
52  DefineVar( "y", &y );
53  DefineVar( "z", &z );
54  DefineVar( "oldVal", &oldVal );
55  DefineFun( "H", nuParser::H );
56  if ( expr.find( "oldVal" ) != string::npos )
57  useOldVal = true;
58  SetExpr( expr );
59  }
60 
62  enum valArgs { EXPR, P, G, EL, LEN, DIA, MAXP, MAXG, MAXL,
63  X, Y, Z, OLDVAL
64  };
65 
66  static double H( double arg ) // Heaviside function.
67  {
68  return ( arg > 0.0);
69  }
70 
71  double eval( vector< double >::const_iterator arg0 )
72  {
73  p = *(arg0 + nuParser::P );
74  g = *(arg0 + nuParser::G );
75  L = *(arg0 + nuParser::EL );
76  len = *(arg0 + nuParser::LEN );
77  dia = *(arg0 + nuParser::DIA );
78  maxP = *(arg0 + nuParser::MAXP );
79  maxG = *(arg0 + nuParser::MAXG );
80  maxL = *(arg0 + nuParser::MAXL );
81  x = *(arg0 + nuParser::X );
82  y = *(arg0 + nuParser::Y );
83  z = *(arg0 + nuParser::Z );
84  oldVal = *(arg0 + nuParser::OLDVAL );
85  return Eval();
86  }
87 
88  static const unsigned int numVal;
89  double p; // geometrical path distance arg
90  double g; // geometrical path distance arg
91  double L; // electrical distance arg
92  double len; // Length of compt in metres
93  double dia; // Diameter of compt in metres
94  double maxP; // Maximum value of p for this neuron.
95  double maxG; // Maximum value of p for this neuron.
96  double maxL; // Maximum value of L for this neuron.
97  double x; // X position of segment in metres
98  double y; // Y position of segment in metres
99  double z; // Z position of segment in metres
100  double oldVal; // Old value of the field, used for relative scaling
101  bool useOldVal; // is the 'oldVal' field needed?
102 };
103 
104 const unsigned int nuParser::numVal = 13;
105 
107 {
109  // ValueFinfos
111  static ValueFinfo< Neuron, double > RM( "RM",
112  "Membrane resistivity, in ohm.m^2. Default value is 1.0.",
113  &Neuron::setRM,
115  );
116  static ValueFinfo< Neuron, double > RA( "RA",
117  "Axial resistivity of cytoplasm, in ohm.m. Default value is 1.0.",
118  &Neuron::setRA,
120  );
121  static ValueFinfo< Neuron, double > CM( "CM",
122  "Membrane Capacitance, in F/m^2. Default value is 0.01",
123  &Neuron::setCM,
125  );
126  static ValueFinfo< Neuron, double > Em( "Em",
127  "Resting membrane potential of compartments, in Volts. "
128  "Default value is -0.065.",
129  &Neuron::setEm,
131  );
132  static ValueFinfo< Neuron, double > theta( "theta",
133  "Angle to rotate cell geometry, around long axis of neuron. "
134  "Think Longitude. Units are radians. "
135  "Default value is zero, which means no rotation. ",
138  );
139  static ValueFinfo< Neuron, double > phi( "phi",
140  "Angle to rotate cell geometry, around elevation of neuron. "
141  "Think Latitude. Units are radians. "
142  "Default value is zero, which means no rotation. ",
145  );
146 
147  static ValueFinfo< Neuron, string > sourceFile( "sourceFile",
148  "Name of source file from which to load a model. "
149  "Accepts swc and dotp formats at present. "
150  "Both these formats require that the appropriate channel "
151  "definitions should have been loaded into /library. ",
154  );
155 
156  static ValueFinfo< Neuron, double > compartmentLengthInLambdas(
157  "compartmentLengthInLambdas",
158  "Units: meters (SI). \n"
159  "Electrotonic length to use for the largest compartment in the "
160  "model. Used to define subdivision of branches into compartments. "
161  "For example, if we set *compartmentLengthInLambdas* to 0.1, "
162  "and *lambda* (electrotonic length) is 250 microns, then it "
163  "sets the compartment length to 25 microns. Thus a dendritic "
164  "branch of 500 microns is subdivided into 20 commpartments. "
165  "If the branch is shorter than *compartmentLengthInLambdas*, "
166  "then it is not subdivided. "
167  "If *compartmentLengthInLambdas* is set to 0 then the original "
168  "compartmental structure of the model is preserved. "
169  " Note that this routine does NOT merge branches, even if "
170  "*compartmentLengthInLambdas* is bigger than the branch. "
171  "While all this subdivision is being done, the Neuron class "
172  "preserves as detailed a geometry as it can, so it can rebuild "
173  "the more detailed version if needed. "
174  "Default value of *compartmentLengthInLambdas* is 0. ",
177  );
178 
180  channelDistribution(
181  "channelDistribution",
182  "Specification for distribution of channels, CaConcens and "
183  "any other model components that are defined as prototypes and "
184  "have to be placed on the electrical compartments.\n"
185  "Arguments: proto path field expr [field expr]...\n"
186  " Each entry is terminated with an empty string. "
187  "The prototype is any object created in */library*, "
188  "If a channel matching the prototype name already exists, then "
189  "all subsequent operations are applied to the extant channel and "
190  "a new one is not created. "
191  "The paired arguments are as follows: \n"
192  "The *field* argument specifies the name of the parameter "
193  "that is to be assigned by the expression.\n"
194  "The *expression* argument is a mathematical expression in "
195  "the muparser framework, which permits most operations including "
196  "trig and transcendental ones. Of course it also handles simple "
197  "numerical values like 1.0, 1e-10 and so on. "
198  "Available arguments for muParser are:\n"
199  " p, g, L, len, dia, maxP, maxG, maxL \n"
200  " p: path distance from soma, measured along dendrite, in metres.\n"
201  " g: geometrical distance from soma, in metres.\n"
202  " L: electrotonic distance (# of lambdas) from soma, along dend. No units.\n"
203  " len: length of compartment, in metres.\n"
204  " dia: for diameter of compartment, in metres.\n"
205  " maxP: Maximum value of *p* for this neuron. \n"
206  " maxG: Maximum value of *g* for this neuron. \n"
207  " maxL: Maximum value of *L* for this neuron.\n"
208  "The expression for the first field must evaluate to > 0 "
209  "for the channel to be installed. For example, for "
210  "channels, if Field == Gbar, and func( r, L, len, dia) < 0, \n"
211  "then the channel is not installed. This feature is typically "
212  "used with the sign() or Heaviside H() function to limit range: "
213  "for example: H(1 - L) will only put channels closer than "
214  "one length constant from the soma, and zero elsewhere. \n"
215  "Available fields are: \n"
216  "Channels: Gbar (install), Ek \n"
217  "CaConcen: shellDia (install), shellFrac (install), tau, min\n"
218  "Unless otherwise noted, all fields are scaled appropriately by "
219  "the dimensions of their compartment. Thus the channel "
220  "maximal conductance Gbar is automatically scaled by the area "
221  "of the compartment, and the user does not need to insert this "
222  "scaling into the calculations.\n"
223  "All parameters are expressed in SI units. Conductance, for "
224  "example, is Siemens/sq metre. "
225  "\n\n"
226  "Some example function forms might be for a channel Gbar: \n"
227  " p < 10e-6 ? 400 : 0.0 \n"
228  " equivalently, \n"
229  " H(10e-6 - p) * 400 \n"
230  " equivalently, \n"
231  " ( sign(10e-6 - p) + 1) * 200 \n"
232  "Each of these forms instruct the function to "
233  "set channel Gbar to 400 S/m^2 only within 10 microns path "
234  "distance of soma\n"
235  "\n"
236  " L < 1.0 ? 100 * exp( -L ) : 0.0 \n"
237  " ->Set channel Gbar to an exponentially falling function of "
238  "electrotonic distance from soma, provided L is under "
239  "1.0 lambdas. \n",
242  );
243 
245  passiveDistribution(
246  "passiveDistribution",
247  "Specification for distribution of passive properties of cell.\n"
248  "Arguments: . path field expr [field expr]...\n"
249  "Note that the arguments list starts with a period. "
250  " Each entry is terminated with an empty string. "
251  "The paired arguments are as follows: \n"
252  "The *field* argument specifies the name of the parameter "
253  "that is to be assigned by the expression.\n"
254  "The *expression* argument is a mathematical expression in "
255  "the muparser framework, which permits most operations including "
256  "trig and transcendental ones. Of course it also handles simple "
257  "numerical values like 1.0, 1e-10 and so on. "
258  "Available arguments for muParser are:\n"
259  " p, g, L, len, dia, maxP, maxG, maxL \n"
260  " p: path distance from soma, measured along dendrite, in metres.\n"
261  " g: geometrical distance from soma, in metres.\n"
262  " L: electrotonic distance (# of lambdas) from soma, along dend. No units.\n"
263  " len: length of compartment, in metres.\n"
264  " dia: for diameter of compartment, in metres.\n"
265  " maxP: Maximum value of *p* for this neuron. \n"
266  " maxG: Maximum value of *g* for this neuron. \n"
267  " maxL: Maximum value of *L* for this neuron.\n"
268  "Available fields are: \n"
269  "RM, RA, CM, Rm, Ra, Cm, Em, initVm \n"
270  "The first three fields are scaled appropriately by "
271  "the dimensions of their compartment. Thus the membrane "
272  "resistivity RM (ohms.m^2) is automatically scaled by the area "
273  "of the compartment, and the user does not need to insert this "
274  "scaling into the calculations to compute Rm."
275  "Using the Rm field lets the user directly assign the "
276  "membrane resistance (in ohms), presumably using len and dia.\n"
277  "Similarly, RA (ohms.m) and CM (Farads/m^2) are specific units "
278  "and the actual values for each compartment are assigned by "
279  "scaling by length and diameter. Ra (ohms) and Cm (Farads) "
280  "require explicit evaluation of the expression. "
281  "All parameters are expressed in SI units. Conductance, for "
282  "example, is Siemens/sq metre.\n"
283  "Note that time these calculations do NOT currently include spines\n",
286  );
287 
288  static ElementValueFinfo< Neuron, vector< string > >spineDistribution(
289  "spineDistribution",
290  "Specification for distribution of spines on dendrite. \n"
291  "Arguments: proto path spacing expr [field expr]...\n"
292  " Each entry is terminated with an empty string. "
293  "The *prototype* is any spine object created in */library*, \n"
294  "The *path* is the wildcard path of compartments on which to "
295  "place the spine.\n"
296  "The *spacing* is the spacing of spines, in metres. \n"
297  "The *expression* argument is a mathematical expression in "
298  "the muparser framework, which permits most operations including "
299  "trig and transcendental ones. Of course it also handles simple "
300  "numerical values like 1.0, 1e-10 and so on. "
301  "The paired arguments are as follows: \n"
302  "The *field* argument specifies the name of the parameter "
303  "that is to be assigned by the expression.\n"
304  "The *expression* argument is a mathematical expression as above. "
305  "Available arguments for muParser are:\n"
306  " p, g, L, len, dia, maxP, maxG, maxL \n"
307  " p: path distance from soma, measured along dendrite, in metres.\n"
308  " g: geometrical distance from soma, in metres.\n"
309  " L: electrotonic distance (# of lambdas) from soma, along dend. No units.\n"
310  " len: length of compartment, in metres.\n"
311  " dia: for diameter of compartment, in metres.\n"
312  " maxP: Maximum value of *p* for this neuron. \n"
313  " maxG: Maximum value of *g* for this neuron. \n"
314  " maxL: Maximum value of *L* for this neuron.\n"
315  "The expression for the *spacing* field must evaluate to > 0 for "
316  "the spine to be installed. For example, if the expresssion is\n"
317  " H(1 - L) \n"
318  "then the systemwill only put spines closer than "
319  "one length constant from the soma, and zero elsewhere. \n"
320  "Available spine parameters are: \n"
321  "spacing, minSpacing, size, sizeDistrib "
322  "angle, angleDistrib \n",
325  );
326 
327 
328  static ReadOnlyValueFinfo< Neuron, unsigned int > numCompartments(
329  "numCompartments",
330  "Number of electrical compartments in model. ",
332  );
333 
335  "numSpines",
336  "Number of dendritic spines in model. ",
338  );
339 
341  "numBranches",
342  "Number of branches in dendrites. ",
344  );
345 
346  static ReadOnlyValueFinfo< Neuron, vector< double > > pathDistFromSoma(
347  "pathDistanceFromSoma",
348  "geometrical path distance of each segment from soma, measured by "
349  "threading along the dendrite.",
351  );
352 
353  static ReadOnlyValueFinfo< Neuron, vector< double > > geomDistFromSoma(
354  "geometricalDistanceFromSoma",
355  "geometrical distance of each segment from soma.",
357  );
358 
359  static ReadOnlyValueFinfo< Neuron, vector< double > > elecDistFromSoma(
360  "electrotonicDistanceFromSoma",
361  "geometrical distance of each segment from soma, as measured along "
362  "the dendrite.",
364  );
365  static ReadOnlyValueFinfo< Neuron, vector< ObjId > > compartments(
366  "compartments",
367  "Vector of ObjIds of electrical compartments. Order matches order "
368  "of segments, and also matches the order of the electrotonic and "
369  "geometricalDistanceFromSoma vectors. ",
371  );
372 
374  compartmentsFromExpression(
375  "compartmentsFromExpression",
376  "Vector of ObjIds of electrical compartments that match the "
377  "'path expression' pair in the argument string.",
379  );
380 
382  valuesFromExpression(
383  "valuesFromExpression",
384  "Vector of values computed for each electrical compartment that "
385  "matches the 'path expression' pair in the argument string."
386  "This has 13 times the number of entries as # of compartments."
387  "For each compartment the entries are: \n"
388  "val, p, g, L, len, dia, maxP, maxG, maxL, x, y, z, 0",
390  );
391 
393  spinesFromExpression(
394  "spinesFromExpression",
395  //"Vector of ObjIds of spines/heads sitting on the electrical "
396  //"compartments that match the 'path expression' pair in the "
397  //"argument string.",
398  "Vector of ObjIds of compartments comprising spines/heads "
399  "that match the 'path expression' pair in the "
400  "argument string.",
402  );
403 
405  spinesOnCompartment(
406  "spinesOnCompartment",
407  "Vector of ObjIds of spines shafts/heads sitting on the specified "
408  "electrical compartment. If each spine has a shaft and a head,"
409  "and there are 10 spines on the compartment, there will be 20 "
410  "entries in the returned vector, ordered "
411  "shaft0, head0, shaft1, head1, ... ",
413  );
414 
416  parentCompartmentOfSpine(
417  "parentCompartmentOfSpine",
418  "Returns parent compartment of specified spine compartment."
419  "Both the spine head or its shaft will return the same parent.",
421  );
422 
424  spineIdsFromCompartmentIds(
425  "spineIdsFromCompartmentIds",
426  "Vector of ObjIds of spine entries (FieldElements on this Neuron, "
427  "used for scaling) that map to the the specified "
428  "electrical compartments. If a bad compartment Id is given, the"
429  "corresponding spine entry is the root Id.",
431  );
432 
434  // DestFinfos
436  static DestFinfo buildSegmentTree( "buildSegmentTree",
437  "Build the reference segment tree structure using the child "
438  "compartments of the current Neuron. Fills in all the coords and "
439  "length constant information into the segments, for later use "
440  "when we build reduced compartment trees and channel "
441  "distributions. Should only be called once, since subsequent use "
442  "on a reduced model will lose the original full cell geometry. ",
444  );
445  static DestFinfo setSpineAndPsdMesh( "setSpineAndPsdMesh",
446  "Assigns the spine and psd mesh to the Neuron. This is used "
447  "to build up a mapping from Spine entries on the Neuron to "
448  "chem spines and PSDs, so that volume change operations from "
449  "the Spine can propagate to the chem systems.",
451  );
452  static DestFinfo setSpineAndPsdDsolve( "setSpineAndPsdDsolve",
453  "Assigns the Dsolves used by spine and PSD to the Neuron. "
454  "This is used "
455  "to handle the rescaling of diffusion rates when spines are "
456  "resized. ",
458  );
459 
460  /*
461  static DestFinfo rotateInSpace( "rotateInSpace",
462  theta, phi
463  static DestFinfo transformInSpace( "transformInSpace",
464  transfMatrix(4x4)
465  static DestFinfo saveAsNeuroML( "saveAsNeuroML", fname )
466  static DestFinfo saveAsDotP( "saveAsDotP", fname )
467  static DestFinfo saveAsSwc( "saveAsSwc", fname )
468  */
470  // FieldElement
472  static FieldElementFinfo< Neuron, Spine > spineFinfo(
473  "spine",
474  "Field Element for spines. Used to handle dynamic "
475  "geometry changes in spines. ",
480  false
481  );
482 
484  static Finfo* neuronFinfos[] =
485  {
486  &RM, // ValueFinfo
487  &RA, // ValueFinfo
488  &CM, // ValueFinfo
489  &Em, // ValueFinfo
490  &theta, // ValueFinfo
491  &phi, // ValueFinfo
492  &sourceFile, // ValueFinfo
493  &compartmentLengthInLambdas, // ValueFinfo
494  &numCompartments, // ReadOnlyValueFinfo
495  &numSpines, // ReadOnlyValueFinfo
496  &numBranches, // ReadOnlyValueFinfo
497  &pathDistFromSoma, // ReadOnlyValueFinfo
498  &geomDistFromSoma, // ReadOnlyValueFinfo
499  &elecDistFromSoma, // ReadOnlyValueFinfo
500  &compartments, // ReadOnlyValueFinfo
501  &channelDistribution, // ValueFinfo
502  &passiveDistribution, // ValueFinfo
503  &spineDistribution, // ValueFinfo
504  // &mechSpec, // ValueFinfo
505  // &spineSpecification, // ValueFinfo
506  &compartmentsFromExpression, // ReadOnlyLookupValueFinfo
507  &valuesFromExpression, // ReadOnlyLookupValueFinfo
508  &spinesFromExpression, // ReadOnlyLookupValueFinfo
509  &spinesOnCompartment, // ReadOnlyLookupValueFinfo
510  &parentCompartmentOfSpine, // ReadOnlyLookupValueFinfo
511  &spineIdsFromCompartmentIds, // ReadOnlyLookupValueFinfo
512  &buildSegmentTree, // DestFinfo
513  &setSpineAndPsdMesh, // DestFinfo
514  &setSpineAndPsdDsolve, // DestFinfo
515  &spineFinfo, // FieldElementFinfo
516  };
517  static string doc[] =
518  {
519  "Name", "Neuron",
520  "Author", "C H Chaitanya, Upi Bhalla",
521  "Description", "Neuron - Manager for neurons. "
522  "Handles high-level specification of distribution of "
523  "spines, channels and passive properties. Also manages "
524  "spine resizing through a Spine FieldElement. ",
525  };
526  static Dinfo<Neuron> dinfo;
527  static Cinfo neuronCinfo(
528  "Neuron",
530  neuronFinfos, sizeof( neuronFinfos ) / sizeof( Finfo* ),
531  &dinfo,
532  doc,
533  sizeof(doc)/sizeof(string)
534  );
535 
536  return &neuronCinfo;
537 }
538 
540 
543  :
544  RM_( 1.0 ),
545  RA_( 1.0 ),
546  CM_( 0.01 ),
547  Em_( -0.065 ),
548  theta_( 0.0 ),
549  phi_( 0.0 ),
550  maxP_( 0.0 ),
551  maxG_( 0.0 ),
552  maxL_( 0.0 ),
553  sourceFile_( "" ),
554  compartmentLengthInLambdas_( 0.2 ),
555  spineEntry_( this )
556 {
557  ;
558 }
559 
560 // When copying Neuron, we next have to rerun buildSegmentTree() and
561 // setSpineAndPsdMesh
562 Neuron::Neuron( const Neuron& other )
563  :
564  RM_( other.RM_ ),
565  RA_( other.RA_ ),
566  CM_( other.CM_ ),
567  Em_( other.Em_ ),
568  theta_( other.theta_ ),
569  phi_( other.phi_ ),
570  maxP_( other.maxP_ ),
571  maxG_( other.maxG_ ),
572  maxL_( other.maxL_ ),
573  sourceFile_( other.sourceFile_ ),
574  compartmentLengthInLambdas_(other.compartmentLengthInLambdas_),
575  channelDistribution_( other.channelDistribution_ ),
576  passiveDistribution_( other.passiveDistribution_ ),
577  spineDistribution_( other.spineDistribution_ ),
578  spineEntry_( this )
579 {
580  ;
581 }
583 // Some static utility functions.
585 
586 
587 bool parseDistrib( vector< vector < string > >& lines,
588  const vector< string >& distrib )
589 {
590  lines.clear();
591  vector< string > temp;
592  for ( unsigned int i = 0; i < distrib.size(); ++i )
593  {
594  if ( distrib[i] == "" )
595  {
596  if ( temp.size() < 4 )
597  {
598  cout << "Warning: Neuron::parseDistrib: <4 args: " <<
599  temp.size() << endl;
600  return false;
601  }
602  if ( temp.size() % 2 == 1 )
603  {
604  cout << "Warning: Neuron::parseDistrib: : odd # of args:"
605  << temp.size() << endl;
606  return false;
607  }
608  lines.push_back( temp );
609  temp.clear();
610  }
611  else
612  {
613  temp.push_back( distrib[i] );
614  }
615  }
616  return true;
617 }
618 
619 static void doClassSpecificMessaging( Shell* shell, Id obj, ObjId compt )
620 {
621  if ( obj.element()->cinfo()->isA( "ChanBase" ) )
622  {
623  shell->doAddMsg( "Single", compt, "channel", obj, "channel" );
624  // Add the message to the Ca pool if our obj has 'Ca' in its name.
625  if ( obj.element()->getName().find( "Ca" ) != string::npos )
626  {
627  // Don't do it if we have the legacy GENESIS format
628  if ( Neutral::child( obj.eref(), "addmsg1" ) == Id() )
629  {
630  vector< ObjId > elist;
631  string path = Neutral::parent( obj ).path() + "/#[ISA=CaConcBase]";
632  // cout << "OK2 to Add Ca Msg for " << path << endl;
633  wildcardFind( path, elist );
634  if ( elist.size() > 0 )
635  {
636  // cout << "Added Ca Msg for " << obj.path() << ", name = " << obj.element()->getName() << endl;
637  ObjId mid = shell->doAddMsg(
638  "single", obj, "IkOut", elist[0], "current" );
639  assert( !mid.bad());
640  }
641  }
642  }
643  }
645 }
646 
647 static bool buildFromProto(
648  const string& name,
649  const vector< ObjId >& elist, const vector< double >& val,
650  vector< ObjId >& mech )
651 {
652  Shell* shell = reinterpret_cast< Shell* >( Id().eref().data() );
653  Id proto( "/library/" + name );
654  if ( proto == Id() )
655  {
656  cout << "Warning: Neuron::buildFromProto: proto '"
657  << name << "' not found, skipping\n";
658  return false;
659  }
660  mech.clear();
661  mech.resize( elist.size() );
662  for ( unsigned int i = 0; i < elist.size(); ++i )
663  {
664  unsigned int j = i * nuParser::numVal;
665  if ( val[ j + nuParser::EXPR ] > 0 )
666  {
667  string name = proto.element()->getName();
668  Id obj = Neutral::child( elist[i].eref(), name );
669  if ( obj == Id() ) // Need to copy it in from proto.
670  {
671  obj = shell->doCopy( proto, elist[i], name, 1, false, false );
672  doClassSpecificMessaging( shell, obj, elist[i] );
673  }
674  mech[i] = obj;
675  }
676  }
677  return true;
678 }
679 
680 static void assignParam( Id obj, const string& field,
681  double val, double len, double dia )
682 {
683  if ( obj.element()->cinfo()->isA( "ChanBase" ) )
684  {
685  if ( field == "Gbar" )
686  {
687  if ( val > 0 )
688  Field< double >::set( obj, "Gbar", val * len * dia * PI );
689  }
690  else if ( field == "Ek" )
691  {
692  Field< double >::set( obj, "Ek", val );
693  }
694  }
695  else if ( obj.element()->cinfo()->isA( "CaConcBase" ) )
696  {
697  Field< double >::set( obj, "length", len );
698  Field< double >::set( obj, "diameter", dia );
699  // cout << "len, dia = " << len << ", " << dia << endl;
700  if ( field == "CaBasal" || field == "tau" || field == "thick" ||
701  field == "floor" || field == "ceiling" )
702  {
703  Field< double >::set( obj, field, val );
704  }
705  else if ( field == "B" )
706  {
707  // The system obeys dC/dt = B*I_Ca - C/tau
708  // So B = arg/( vol * F ). Here the system provides vol and F,
709  // so the arg is just a scale factor over this, typically
710  // to be thought of in terms of buffering. Small B is more
711  // buffering. This field is deprecated but used in legacy
712  // GENESIS scripts.
713  Field< double >::set( obj, "B", val /
714  ( FaradayConst * len * dia * dia * PI / 4.0 ) );
715  }
716  }
717 }
718 
720  double val, const string& field, double len, double dia )
721 {
722  if ( field == "initVm" || field == "INITVM" )
723  {
724  Field< double >::set( compt, "initVm", val );
725  return;
726  }
727  if ( field == "Em" || field == "EM" )
728  {
729  Field< double >::set( compt, "Em", val );
730  return;
731  }
732  if ( val > 0.0 )
733  {
734  if ( field == "Rm" || field == "Ra" || field == "Cm" )
735  {
736  Field< double >::set( compt, field, val );
737  }
738  else if ( field == "RM" )
739  {
740  Field< double >::set( compt, "Rm", val / ( len * dia * PI ) );
741  }
742  else if ( field == "RA" )
743  {
744  Field< double >::set( compt, "Ra", val*len*4 / (dia*dia*PI) );
745  }
746  else if ( field == "CM" )
747  {
748  Field< double >::set( compt, "Cm", val * len * dia * PI );
749  }
750  else
751  {
752  cout << "Warning: setCompartmentParam: field '" << field <<
753  "' not found\n";
754  }
755  }
756 }
757 
759  const vector< ObjId >& elist, const vector< double >& val,
760  const string& field, const string& expr )
761 {
762  try
763  {
764  nuParser parser( expr );
765  for ( unsigned int i = 0; i < elist.size(); ++i )
766  {
767  unsigned int j = i * nuParser::numVal;
768  if ( val[ j + nuParser::EXPR ] > 0 )
769  {
770  double len = val[j + nuParser::LEN ];
771  double dia = val[j + nuParser::DIA ];
772  double x = parser.eval( val.begin() + j );
774  x, field, len, dia );
775  }
776  }
777  }
778  catch ( mu::Parser::exception_type& err )
779  {
780  cout << err.GetMsg() << endl;
781  }
782 }
783 
784 static void setMechParams(
785  const vector< ObjId >& mech,
786  const vector< ObjId >& elist, const vector< double >& val,
787  const string& field, const string& expr )
788 {
789  try
790  {
791  nuParser parser ( expr );
792  for ( unsigned int i = 0; i < elist.size(); ++i )
793  {
794  unsigned int j = i * nuParser::numVal;
795  if ( val[ j + nuParser::EXPR ] > 0 )
796  {
797  double len = val[j + nuParser::LEN ];
798  double dia = val[j + nuParser::DIA ];
799  double x = parser.eval( val.begin() + j );
800  assignParam( mech[i], field, x, len, dia );
801  }
802  }
803  }
804  catch ( mu::Parser::exception_type& err )
805  {
806  cout << err.GetMsg() << endl;
807  }
808 }
809 
811 // ValueFinfos
813 
814 void Neuron::setRM( double v )
815 {
816  if ( v > 0.0 )
817  RM_ = v;
818  else
819  cout << "Warning:: Neuron::setRM: value must be +ve, is " << v << endl;
820 }
821 double Neuron::getRM() const
822 {
823  return RM_;
824 }
825 
826 void Neuron::setRA( double v )
827 {
828  if ( v > 0.0 )
829  RA_ = v;
830  else
831  cout << "Warning:: Neuron::setRA: value must be +ve, is " << v << endl;
832 }
833 double Neuron::getRA() const
834 {
835  return RA_;
836 }
837 
838 void Neuron::setCM( double v )
839 {
840  if ( v > 0.0 )
841  CM_ = v;
842  else
843  cout << "Warning:: Neuron::setCM: value must be +ve, is " << v << endl;
844 }
845 double Neuron::getCM() const
846 {
847  return CM_;
848 }
849 
850 
851 void Neuron::setEm( double v )
852 {
853  Em_ = v;
854 }
855 double Neuron::getEm() const
856 {
857  return Em_;
858 }
859 
860 
861 void Neuron::setTheta( double v )
862 {
863  theta_ = v;
864  // Do stuff here for rotating it.
865 }
866 double Neuron::getTheta() const
867 {
868  return theta_;
869 }
870 
871 
872 void Neuron::setPhi( double v )
873 {
874  phi_ = v;
875  // Do stuff here for rotating it.
876 }
877 double Neuron::getPhi() const
878 {
879  return phi_;
880 }
881 
882 
883 void Neuron::setSourceFile( string v )
884 {
885  sourceFile_ = v;
886  // Stuff here for loading it.
887 }
888 
889 string Neuron::getSourceFile() const
890 {
891  return sourceFile_;
892 }
893 
894 
896 {
898 }
900 {
902 }
903 
904 unsigned int Neuron::getNumCompartments() const
905 {
906  return segId_.size();
907 }
908 
909 /*
910 unsigned int Neuron::getNumSpines() const
911 {
912  return spineParentIndex_.size();
913 }
914 */
915 
916 unsigned int Neuron::getNumBranches() const
917 {
918  return branches_.size();
919 }
920 
921 vector< double> Neuron::getPathDistFromSoma() const
922 {
923  vector< double > ret( segs_.size(), 0.0 );
924  for ( unsigned int i = 0; i < segs_.size(); ++i )
925  ret[i] = segs_[i].getPathDistFromSoma();
926  return ret;
927 }
928 
929 vector< double> Neuron::getGeomDistFromSoma() const
930 {
931  vector< double > ret( segs_.size(), 0.0 );
932  for ( unsigned int i = 0; i < segs_.size(); ++i )
933  ret[i] = segs_[i].getGeomDistFromSoma();
934  return ret;
935 }
936 
937 vector< double> Neuron::getElecDistFromSoma() const
938 {
939  vector< double > ret( segs_.size(), 0.0 );
940  for ( unsigned int i = 0; i < segs_.size(); ++i )
941  ret[i] = segs_[i].getElecDistFromSoma();
942  return ret;
943 }
944 
945 vector< ObjId > Neuron::getCompartments() const
946 {
947  vector< ObjId > ret( segId_.size() );
948  for ( unsigned int i = 0; i < segId_.size(); ++i )
949  ret[i] = segId_[i];
950  return ret;
951 }
952 
959 vector< ObjId > Neuron::getExprElist( const Eref& e, string line ) const
960 {
961  Shell* shell = reinterpret_cast< Shell* >( Id().eref().data() );
962  vector< ObjId > ret;
963  vector< ObjId > elist;
964  vector< double > val;
965  unsigned long pos = line.find_first_of( " \t" );
966  string path = line.substr( 0, pos );
967  string expr = line.substr( pos );
968  ObjId oldCwe = shell->getCwe();
969  shell->setCwe( e.objId() );
970  wildcardFind( path, elist );
971  shell->setCwe( oldCwe );
972  if ( elist.size() == 0 )
973  return ret;
974  evalExprForElist( elist, expr, val );
975  ret.reserve( elist.size() );
976  for ( unsigned int i = 0; i < elist.size(); ++i )
977  {
978  if ( val[i * nuParser::numVal] > 0 )
979  ret.push_back( elist[i] );
980  }
981  return ret;
982 }
983 
991 vector< double > Neuron::getExprVal( const Eref& e, string line ) const
992 {
993  Shell* shell = reinterpret_cast< Shell* >( Id().eref().data() );
994  vector< ObjId > elist;
995  vector< double > val;
996  unsigned long pos = line.find_first_of( " \t" );
997  string path = line.substr( 0, pos );
998  string expr = line.substr( pos );
999  ObjId oldCwe = shell->getCwe();
1000  shell->setCwe( e.objId() );
1001  wildcardFind( path, elist );
1002  shell->setCwe( oldCwe );
1003  if ( elist.size() == 0 )
1004  return val;
1005  evalExprForElist( elist, expr, val );
1006  return val;
1007 }
1008 
1010  const Eref& e, string line ) const
1011 {
1012  unsigned long pos = line.find_first_of( " \t" );
1013  string path = line.substr( 0, pos );
1014  string expr = line.substr( pos );
1015 
1016  // Look for all compartments that fit the expression.
1017  vector< ObjId > temp = getExprElist( e, "# " + expr );
1018  // indexed by segIndex, includes all compts in all spines.
1019  /*
1020  vector< vector< Id > > allSpinesPerCompt( segId_.size() );
1021  for ( unsigned int i = 0; i < spines_.size(); ++i ) {
1022  assert( allSpinesPerCompt.size() > spineParentSegIndex_[i] );
1023  vector< Id >& s = allSpinesPerCompt[ spineParentSegIndex_[i] ];
1024  s.insert( s.end(), spines_[i].begin(), spines_[i].end() );
1025  }
1026  */
1027  vector< ObjId >ret;
1028  if ( allSpinesPerCompt_.size() == 0 )
1029  return ret;
1030  for ( vector< ObjId >::iterator
1031  i = temp.begin(); i != temp.end(); ++i )
1032  {
1033  map< Id, unsigned int >::const_iterator si =
1034  segIndex_.find( i->id );
1035  assert( si != segIndex_.end() );
1036  assert( si->second < segId_.size() );
1037  if ( allSpinesPerCompt_.size() > si->second )
1038  {
1039  const vector< Id >& s = allSpinesPerCompt_[ si->second ];
1040  for ( vector< Id >::const_iterator j = s.begin(); j != s.end(); ++j )
1041  {
1042  if ( matchBeforeBrace( *j, path ) )
1043  ret.push_back( *j );
1044  }
1045  }
1046  }
1047  return ret;
1048 }
1049 
1051  const Eref& e, ObjId compt ) const
1052 {
1053  vector< ObjId > ret;
1054  map< Id, unsigned int >::const_iterator pos =
1055  segIndex_.find( compt.id );
1056  if ( pos != segIndex_.end() )
1057  {
1058  assert( pos->second < allSpinesPerCompt_.size() );
1059  const vector< Id >& spines = allSpinesPerCompt_[pos->second];
1060  for ( unsigned int i = 0; i < spines.size(); ++i )
1061  ret.push_back( spines[i] );
1062  }
1063  return ret;
1064 }
1065 
1067  const Eref& e, ObjId compt ) const
1068 {
1069  for ( unsigned int comptIndex = 0; comptIndex < allSpinesPerCompt_.size(); ++comptIndex )
1070  {
1071  const vector< Id >& v = allSpinesPerCompt_[comptIndex];
1072  for ( unsigned int j = 0; j < v.size(); j++ )
1073  if ( v[j] == compt.id )
1074  return segId_[ comptIndex ];
1075  }
1076  return ObjId();
1077 }
1078 
1080  const Eref& e, vector< ObjId > compt ) const
1081 {
1082  vector< ObjId > ret;
1083  map< Id, unsigned int > lookupSpine;
1084  Id spineBase = Id( e.id().value() + 1 );
1085  for ( unsigned int i = 0; i < spines_.size(); ++i )
1086  {
1087  for ( vector< Id >::const_iterator j = spines_[i].begin(); j != spines_[i].end(); ++j )
1088  {
1089  lookupSpine[ *j ] = i;
1090  }
1091  }
1092  // cout << "################## " << lookupSpine.size() << endl;
1093  for ( map< Id, unsigned int >::const_iterator k = lookupSpine.begin(); k != lookupSpine.end(); ++k )
1094  {
1095  // cout << "spine[" << k->second << "] has " << k->first.element()->getName() << endl;
1096  // cout << "spine[" << k->second << "] has " << k->first << endl;
1097 
1098  }
1099  for ( vector< ObjId >::const_iterator j = compt.begin(); j != compt.end(); ++j )
1100  {
1101  // cout << "compt: " << *j << " " << j->element()->getName() << endl;
1102  map< Id, unsigned int >::const_iterator k = lookupSpine.find( j->id );
1103  if ( k != lookupSpine.end() )
1104  {
1105  ret.push_back( ObjId( spineBase, e.dataIndex(), k->second ) );
1106  // cout << "spine[" << k->second << "] has " << j->element()->getName() << endl;
1107  }
1108  else
1109  {
1110  ret.push_back( ObjId() );
1111  }
1112  }
1113  return ret;
1114 }
1115 
1116 void Neuron::buildElist( const Eref& e,
1117  const vector< string >& line,
1118  vector< ObjId >& elist,
1119  vector< double >& val )
1120 {
1121  Shell* shell = reinterpret_cast< Shell* >( Id().eref().data() );
1122  const string& path = line[1];
1123  const string& expr = line[3];
1124  ObjId oldCwe = shell->getCwe();
1125  shell->setCwe( e.objId() );
1126  wildcardFind( path, elist );
1127  sort( elist.begin(), elist.end() );
1128  shell->setCwe( oldCwe );
1129  evalExprForElist( elist, expr, val );
1130 }
1131 
1132 void Neuron::setChannelDistribution( const Eref& e, vector< string > v )
1133 {
1134  // Here we should clear the extant channels, if any.
1135  vector< vector< string > > lines;
1136  if ( parseDistrib( lines, v ) )
1137  {
1139  for ( unsigned int i = 0; i < lines.size(); ++i )
1140  {
1141  vector< string >& temp = lines[i];
1142  vector< ObjId > elist;
1143  vector< double > val;
1144  buildElist( e, temp, elist, val );
1145 
1146  vector< ObjId > mech( elist.size() );
1147  if ( buildFromProto( temp[0], elist, val, mech ) )
1148  {
1149  for ( unsigned int j = 2; j < temp.size(); j += 2 )
1150  {
1151  setMechParams( mech, elist, val, temp[j], temp[j+1] );
1152  }
1153  }
1154  }
1155  }
1156 }
1157 
1158 vector< string > Neuron::getChannelDistribution( const Eref& e ) const
1159 {
1160  return channelDistribution_;
1161 }
1162 
1163 void Neuron::setPassiveDistribution( const Eref& e, vector< string > v )
1164 {
1165  vector< vector< string > > lines;
1166  if ( parseDistrib( lines, v ) )
1167  {
1169  for ( unsigned int i = 0; i < lines.size(); ++i )
1170  {
1171  vector< string >& temp = lines[i];
1172  vector< ObjId > elist;
1173  vector< double > val;
1174  buildElist( e, temp, elist, val );
1175  for ( unsigned int j = 2; j < temp.size(); j += 2 )
1176  {
1177  setCompartmentParams( elist, val, temp[j], temp[j+1] );
1178  }
1179  }
1180  }
1181 }
1182 
1183 vector< string > Neuron::getPassiveDistribution( const Eref& e ) const
1184 {
1185  return passiveDistribution_;
1186 }
1187 
1188 void Neuron::setSpineDistribution( const Eref& e, vector< string > v )
1189 {
1190  // Here we should clear the extant spines, if any.
1191  vector< vector< string > > lines;
1192  if ( parseDistrib( lines, v ) )
1193  {
1194  spineDistribution_ = v;
1195  for ( unsigned int i = 0; i < lines.size(); ++i )
1196  {
1197  vector< ObjId > elist;
1198  vector< double > val;
1199  buildElist( e, lines[i], elist, val );
1200  installSpines( elist, val, lines[i] );
1201  }
1202  }
1203 }
1204 
1205 vector< string > Neuron::getSpineDistribution( const Eref& e ) const
1206 {
1207  return spineDistribution_;
1208 }
1209 
1210 
1212 // Stuff here for parsing the compartment tree
1214 
1215 static Id getComptParent( Id id )
1216 {
1217  // raxial points towards soma.
1218  static const Finfo* raxialFinfo =
1219  Cinfo::find( "Compartment" )->findFinfo( "raxialOut" );
1220  static const Finfo* proximalFinfo =
1221  Cinfo::find( "SymCompartment" )->findFinfo( "proximalOut" );
1222 
1223  if ( id.element()->cinfo()->isA( "CompartmentBase" ) )
1224  {
1225  vector< Id > ret;
1226  id.element()->getNeighbors( ret, raxialFinfo );
1227  if ( ret.size() == 1 )
1228  return ret[0];
1229  // If it didn't find an axial, maybe it is a symCompt
1230  if ( id.element()->cinfo()->isA( "SymCompartment" ) )
1231  {
1232  id.element()->getNeighbors( ret, proximalFinfo );
1233  if ( ret.size() == 1 )
1234  return ret[0];
1235  }
1236  }
1237  return Id();
1238 }
1239 
1240 // Returns Id of soma
1242  const vector< Id >& kids, map< Id, unsigned int >& segIndex )
1243 {
1244  Id soma;
1245  segIndex.clear();
1246  Id fatty;
1247  double maxDia = 0.0;
1248  unsigned int numKids = 0;
1249  for ( unsigned int i = 0; i < kids.size(); ++i )
1250  {
1251  const Id& k = kids[i];
1252  if ( k.element()->cinfo()->isA( "CompartmentBase" ) )
1253  {
1254  segIndex[ k ] = numKids++;
1255  const string& s = k.element()->getName();
1256  if ( s.find( "soma" ) != s.npos ||
1257  s.find( "Soma" ) != s.npos ||
1258  s.find( "SOMA" ) != s.npos )
1259  {
1260  soma = k;
1261  }
1262  double dia = Field< double >::get( k, "diameter" );
1263  if ( dia > maxDia )
1264  {
1265  maxDia = dia;
1266  fatty = k;
1267  }
1268  }
1269  }
1270  if ( soma != Id() )
1271  return soma;
1272  return fatty; // Fallback.
1273 }
1274 
1275 static void fillSegments( vector< SwcSegment >& segs,
1276  const map< Id, unsigned int >& segIndex,
1277  const vector< Id >& kids )
1278 {
1279  segs.clear();
1280  for ( unsigned int i = 0; i < kids.size(); ++i )
1281  {
1282  const Id& k = kids[i];
1283  if ( k.element()->cinfo()->isA( "CompartmentBase" ) )
1284  {
1285  double x = Field< double >::get( k, "x" );
1286  double y = Field< double >::get( k, "y" );
1287  double z = Field< double >::get( k, "z" );
1288  double dia = Field< double >::get( k, "diameter" );
1289  Id pa = getComptParent( k );
1290  unsigned int paIndex = ~0U; // soma
1291  int comptType = 1; // soma
1292  if ( pa != Id() )
1293  {
1294  map< Id, unsigned int >::const_iterator
1295  j = segIndex.find( pa );
1296  if ( j != segIndex.end() )
1297  {
1298  paIndex = j->second;
1299  comptType = 3; // generic dendrite
1300  }
1301  }
1302  // cout << "Seg[" << i << "].xy = " << int(x*1e6) << " " << int(y*1e6) << endl;
1303 
1304  segs.push_back(
1305  SwcSegment( i, comptType, x, y, z, dia/2.0, paIndex ) );
1306  }
1307  }
1308 }
1309 
1312  SwcSegment& self, vector< SwcSegment >& segs,
1313  const vector< Id >& lookupId,
1314  double len, double L, double pSoma, double eSoma )
1315 {
1316  self.setCumulativeDistance( len, L, pSoma, eSoma );
1317  for ( unsigned int i = 0; i < self.kids().size(); ++i )
1318  {
1319  SwcSegment& kid = segs[ self.kids()[i] ];
1320  double segmentLength = kid.distance( self );
1321  double p = pSoma + segmentLength;
1322  Id kidId = lookupId[ self.kids()[i] ];
1323  double Rm = Field< double >::get( kidId, "Rm" );
1324  double Ra = Field< double >::get( kidId, "Ra" );
1325  // Note that sqrt( Rm/Ra ) = lambda/length = 1/L.
1326  double electrotonicLength = sqrt( Ra / Rm );
1327  double e = eSoma + electrotonicLength;
1328  traverseCumulativeDistance( kid, segs, lookupId,
1329  segmentLength, electrotonicLength, p, e );
1330  }
1331 }
1332 
1334 {
1335  double len = Field< double >::get( soma_, "length" );
1336  double dia = Field< double >::get( soma_, "diameter" );
1337  if ( len < dia )
1338  len = dia;
1339  double Rm = Field< double >::get( soma_, "Rm" );
1340  double Ra = Field< double >::get( soma_, "Ra" );
1341  double L = sqrt( Ra / Rm );
1342 
1343  for ( unsigned int i = 0; i < segs_.size(); ++i )
1344  {
1345  segs_[i].setGeometricalDistanceFromSoma( segs_[0] );
1346  }
1347 
1348  traverseCumulativeDistance( segs_[0], segs_, segId_, len, L, 0, 0 );
1349  maxL_ = maxG_ = maxP_ = 0.0;
1350  for ( unsigned int i = 0; i < segs_.size(); ++i )
1351  {
1352  double p = segs_[i].getPathDistFromSoma();
1353  if ( maxP_ < p ) maxP_ = p;
1354  double g = segs_[i].getGeomDistFromSoma();
1355  if ( maxG_ < g ) maxG_ = g;
1356  double L = segs_[i].getElecDistFromSoma();
1357  if ( maxL_ < L ) maxL_ = L;
1358  }
1359 }
1360 
1363 {
1364  vector< Id > kids;
1365  Neutral::children( e, kids );
1366  sort( kids.begin(), kids.end() );
1367 
1368  soma_ = fillSegIndex( kids, segIndex_ );
1369  if ( kids.size() == 0 || soma_ == Id() )
1370  {
1371  cout << "Error: Neuron::buildSegmentTree( " << e.id().path() <<
1372  " ): \n Valid neuronal model not found.\n";
1373  return;
1374  }
1375  fillSegments( segs_, segIndex_, kids );
1376  int numPa = 0;
1377  for ( unsigned int i = 0; i < segs_.size(); ++i )
1378  {
1379  if ( segs_[i].parent() == ~0U )
1380  {
1381  numPa++;
1382  }
1383  else
1384  {
1385  segs_[ segs_[i].parent() ].addChild( i );
1386  }
1387  }
1388  for ( unsigned int i = 0; i < segs_.size(); ++i )
1389  {
1390  segs_[i].figureOutType();
1391  }
1392 
1393  if ( numPa != 1 )
1394  {
1395  cout << "Warning: Neuron.cpp: buildTree: numPa = " << numPa << endl;
1396  }
1397  segId_.clear();
1398  segId_.resize( segIndex_.size(), Id() );
1399  for ( map< Id, unsigned int >::const_iterator
1400  i = segIndex_.begin(); i != segIndex_.end(); ++i )
1401  {
1402  assert( i->second < segId_.size() );
1403  segId_[ i->second ] = i->first;
1404  }
1406 }
1407 
1408 
1410 void Neuron::setSpineAndPsdMesh( Id spineMesh, Id psdMesh )
1411 {
1412  if ( !spineMesh.element()->cinfo()->isA( "SpineMesh" ) )
1413  {
1414  cout << "Error: Neuron::setSpineAndPsdMesh: '" <<
1415  spineMesh.path() << "' is not a SpineMesh\n";
1416  return;
1417  }
1418  if ( !psdMesh.element()->cinfo()->isA( "PsdMesh" ) )
1419  {
1420  cout << "Error: Neuron::setSpineAndPsdMesh: '" <<
1421  psdMesh.path() << "' is not a PsdMesh\n";
1422  return;
1423  }
1424  Id spineStoich = Neutral::child( spineMesh.eref(), "stoich" );
1425  Id psdStoich = Neutral::child( psdMesh.eref(), "stoich" );
1426  if ( spineStoich == Id() || psdStoich == Id() )
1427  {
1428  cout << "Error: Neuron::setSpineAndPsdMesh: Stoich child not found\n";
1429  return;
1430  }
1431 
1432  vector< Id > spineList = Field< vector< Id > >::get(
1433  spineMesh, "elecComptList" );
1434  vector< Id > psdList = Field< vector< Id > >::get(
1435  psdMesh, "elecComptList" );
1436  assert( spineList.size()== psdList.size() );
1437  map< Id, unsigned int > spineMap; // spineMap[ SpineOnNeuron ] = index
1438  for ( unsigned int i = 0; i < spines_.size(); ++i )
1439  {
1440  assert( spines_[i].size() > 1 );
1441  spineMap[ spines_[i][1] ] = i;
1442  }
1443  // We don't want to clear this because we can use a single vector
1444  // to overlay a number of spine meshes, since each will be a distinct
1445  // subset of the full list of spines. None is used twice.
1446  // spineToMeshOrdering_.clear();
1447  for( unsigned int i = 0; i < spineList.size(); ++i )
1448  {
1449  map< Id, unsigned int >::iterator j = spineMap.find( spineList[i]);
1450  if ( j == spineMap.end() )
1451  {
1452  cout << "Error: Neuron::setSpineAndPsdMesh: spine '" <<
1453  spineList[i].path() << "' not found on Neuron\n";
1454  return;
1455  }
1456  spineToMeshOrdering_[ j->second ] = i;
1457  spineStoich_[ j->second ] = spineStoich;
1458  psdStoich_[ j->second ] = psdStoich;
1459  }
1460 }
1461 
1462 void Neuron::setSpineAndPsdDsolve( Id spineDsolve, Id psdDsolve )
1463 {
1464  headDsolve_ = spineDsolve;
1465  psdDsolve_ = psdDsolve;
1466 }
1467 
1469 // Here we set up the more general specification of mechanisms. Each
1470 // line is
1471 // proto path field expr [field expr]...
1473 
1478 void Neuron::evalExprForElist( const vector< ObjId >& elist,
1479  const string& expn, vector< double >& val ) const
1480 {
1481  val.clear();
1482  val.resize( elist.size() * nuParser::numVal );
1483  // Build the function
1484  double len = 0; // Length of compt in metres
1485  double dia = 0; // Diameter of compt in metres
1486  unsigned int valIndex = 0;
1487  try
1488  {
1489  nuParser parser( expn );
1490 
1491  // Go through the elist checking for the channels. If not there,
1492  // build them.
1493  for ( vector< ObjId >::const_iterator
1494  i = elist.begin(); i != elist.end(); ++i )
1495  {
1496  if ( i->element()->cinfo()->isA( "CompartmentBase" ) )
1497  {
1498  map< Id, unsigned int >:: const_iterator j =
1499  segIndex_.find( *i );
1500  if ( j != segIndex_.end() )
1501  {
1502  dia = Field< double >::get( *i, "diameter" );
1503  len = Field< double >::get( *i, "length" );
1504  assert( j->second < segs_.size() );
1505  val[valIndex + nuParser::P] =
1506  segs_[j->second].getPathDistFromSoma();
1507  val[valIndex + nuParser::G] =
1508  segs_[j->second].getGeomDistFromSoma();
1509  val[valIndex + nuParser::EL] =
1510  segs_[j->second].getElecDistFromSoma();
1511  val[valIndex + nuParser::LEN] = len;
1512  val[valIndex + nuParser::DIA] = dia;
1513  val[valIndex + nuParser::MAXP] = maxP_;
1514  val[valIndex + nuParser::MAXG] = maxG_;
1515  val[valIndex + nuParser::MAXL] = maxL_;
1516  val[valIndex + nuParser::X] = segs_[j->second].vec().a0();
1517  val[valIndex + nuParser::Y] = segs_[j->second].vec().a1();
1518  val[valIndex + nuParser::Z] = segs_[j->second].vec().a2();
1519  // Can't assign oldVal on first arg
1520  val[valIndex + nuParser::OLDVAL] = 0.0;
1521 
1522  val[valIndex + nuParser::EXPR] = parser.eval(
1523  val.begin() + valIndex );
1524  }
1525  }
1526  valIndex += nuParser::numVal;
1527  }
1528  }
1529  catch ( mu::Parser::exception_type& err )
1530  {
1531  cout << err.GetMsg() << endl;
1532  }
1533 }
1534 
1535 
1537 // Stuff here for inserting spines.
1539 
1546 static double coordSystem( Id soma, Id dend, Vec& x, Vec& y, Vec& z )
1547 {
1548  static const double EPSILON = 1e-20;
1549  double x0 = Field< double >::get( dend, "x0" );
1550  double y0 = Field< double >::get( dend, "y0" );
1551  double z0 = Field< double >::get( dend, "z0" );
1552  double x1 = Field< double >::get( dend, "x" );
1553  double y1 = Field< double >::get( dend, "y" );
1554  double z1 = Field< double >::get( dend, "z" );
1555 
1556  Vec temp( x1-x0, y1-y0, z1-z0 );
1557  double len = temp.length();
1558  z = Vec( temp.a0()/len, temp.a1()/len, temp.a2()/len );
1559 
1560  double sx0 = Field< double >::get( soma, "x0" );
1561  double sy0 = Field< double >::get( soma, "y0" );
1562  double sz0 = Field< double >::get( soma, "z0" );
1563  Vec temp2( x0 - sx0, y0-sy0, z0-sz0 );
1564  Vec y2 = temp.crossProduct( z );
1565  double ylen = y2.length();
1566  double ytemp = 1.0;
1567  while ( ylen < EPSILON )
1568  {
1569  Vec t( ytemp , sqrt( 2.0 ), 0.0 );
1570  y2 = t.crossProduct( z );
1571  ylen = y2.length();
1572  ytemp += 1.0;
1573  }
1574  y = Vec( y2.a0()/ylen, y2.a1()/ylen, y2.a2()/ylen );
1575  x = z.crossProduct( y );
1576  assert( doubleEq( x.length(), 1.0 ) );
1577  return len;
1578 }
1579 
1583 static void reorientSpine( vector< Id >& spineCompts,
1584  vector< Vec >& coords,
1585  Vec& parentPos, double pos, double angle,
1586  Vec& x, Vec& y, Vec& z )
1587 {
1588  double c = cos( angle );
1589  double s = sin( angle );
1590  double omc = 1.0 - c;
1591 
1592  Vec rot0( z.a0()*z.a0()*omc + c,
1593  z.a1()*z.a0()*omc - z.a2()*s ,
1594  z.a2()*z.a0()*omc + z.a1()*s );
1595 
1596  Vec rot1( z.a0()*z.a1()*omc + z.a2()*s,
1597  z.a1()*z.a1()*omc + c,
1598  z.a2()*z.a1()*omc - z.a0()*s );
1599 
1600  Vec rot2( z.a0()*z.a2()*omc - z.a1()*s,
1601  z.a1()*z.a2()*omc + z.a0()*s,
1602  z.a2()*z.a2()*omc + c );
1603 
1604  Vec translation = z * pos + parentPos;
1605  // Vec translation = parentPos;
1606  vector< Vec > ret( coords.size() );
1607  for ( unsigned int i = 0; i < coords.size(); ++i )
1608  {
1609  ret[i] = Vec( rot0.dotProduct( coords[i] ) + translation.a0(),
1610  rot1.dotProduct( coords[i] ) + translation.a1(),
1611  rot2.dotProduct( coords[i] ) + translation.a2() );
1612 
1613  }
1614  assert( spineCompts.size() * 2 == ret.size() );
1615 
1616  for ( unsigned int i = 0; i < spineCompts.size(); ++i )
1617  {
1618  unsigned int j = 2 * i;
1619  Field< double >::set( spineCompts[i], "x0", ret[j].a0() );
1620  Field< double >::set( spineCompts[i], "y0", ret[j].a1() );
1621  Field< double >::set( spineCompts[i], "z0", ret[j].a2() );
1622  // cout << "(" << ret[j].a0() << ", " << ret[j].a1() << ", " << ret[j].a2() << ")";
1623  j = j + 1;
1624  Field< double >::set( spineCompts[i], "x", ret[j].a0() );
1625  Field< double >::set( spineCompts[i], "y", ret[j].a1() );
1626  Field< double >::set( spineCompts[i], "z", ret[j].a2() );
1627  // cout << "(" << ret[j].a0() << ", " << ret[j].a1() << ", " << ret[j].a2() << ")\n";
1628  }
1629 }
1630 
1649 static vector< Id > addSpine( Id parentCompt, Id spineProto,
1650  double pos, double angle,
1651  Vec& x, Vec& y, Vec& z,
1652  double size,
1653  unsigned int k )
1654 {
1655  Shell* shell = reinterpret_cast< Shell* >( Id().eref().data() );
1656  Id parentObject = Neutral::parent( parentCompt );
1657  stringstream sstemp;
1658  sstemp << k;
1659  string kstr = sstemp.str();
1660  Id spine = shell->doCopy( spineProto, parentObject, "_spine" + kstr,
1661  1, false, false );
1662  vector< Id > kids;
1663  Neutral::children( spine.eref(), kids );
1664  double x0 = Field< double >::get( parentCompt, "x0" );
1665  double y0 = Field< double >::get( parentCompt, "y0" );
1666  double z0 = Field< double >::get( parentCompt, "z0" );
1667  double parentRadius = Field< double >::get( parentCompt, "diameter" )/2;
1668  Vec ppos( x0, y0, z0 );
1669  // First, build the coordinates vector for the spine. Assume that its
1670  // major axis is along the unit vector [1,0,0].
1671  vector< Vec > coords;
1672  vector< Id > ret; // Filtered to make sure that it returns only compts
1673  for ( vector< Id >::iterator i = kids.begin(); i != kids.end(); ++i )
1674  {
1675  if ( i->element()->cinfo()->isA( "CompartmentBase" ) )
1676  {
1677  i->element()->setName( i->element()->getName() + kstr );
1678  x0 = Field< double >::get( *i, "x0" ) * size;
1679  y0 = Field< double >::get( *i, "y0" ) * size;
1680  z0 = Field< double >::get( *i, "z0" ) * size;
1681  coords.push_back( Vec( x0 + parentRadius, y0, z0 ) );
1682  double x = Field< double >::get( *i, "x" ) * size;
1683  double y = Field< double >::get( *i, "y" ) * size;
1684  double z = Field< double >::get( *i, "z" ) * size;
1685  double dia = Field< double >::get( *i, "diameter" ) * size;
1686  // Field< double >::set( *i, "diameter", dia );
1687 
1688  double len = sqrt(
1689  (x-x0)*(x-x0) +
1690  (y-y0)*(y-y0) +
1691  (z-z0)*(z-z0) );
1692  SetGet2< double, double >::set( *i, "setGeomAndElec", len, dia );
1693 
1694 
1695  coords.push_back( Vec( x + parentRadius, y, z ) );
1696  // scaleSpineCompt( *i, size );
1697  shell->doMove( *i, parentObject );
1698  ret.push_back( *i );
1699  }
1700  }
1701  // Then, take the projection of this along the x vector passed in.
1702  for( vector< Vec >::iterator i = coords.begin(); i != coords.end(); ++i)
1703  *i = x * i->a0();
1704  shell->doDelete( spine ); // get rid of the holder for the spine copy.
1705  shell->doAddMsg( "Single", parentCompt, "axial", kids[0], "raxial" );
1706  reorientSpine( kids, coords, ppos, pos, angle, x, y, z );
1707 
1708  return ret;
1709 }
1710 
1712 // Here are the mechSpec format line parsers
1714 
1715 // Return value for field if found, otherwise return a default string.
1716 string findArg( const vector<string>& line, const string& field )
1717 {
1718  // line has: proto path [field val]...
1719  assert( (line.size() % 2) != 1 );
1720  for ( unsigned int i = 2; i < line.size(); i+=2 )
1721  if ( line[i] == field )
1722  return line[i+1];
1723  string ret = "";
1724  if ( field == "spacing" )
1725  {
1726  ret = "1.0e-6";
1727  }
1728  else if ( field == "spacingDistrib" )
1729  {
1730  ret = "0";
1731  }
1732  else if ( field == "size" )
1733  {
1734  ret = "1";
1735  }
1736  else if ( field == "sizeDistrib" )
1737  {
1738  ret = "0";
1739  }
1740  else if ( field == "angle" )
1741  {
1742  ret = "0";
1743  }
1744  else if ( field == "angleDistrib" )
1745  {
1746  ret = "6.283185307";
1747  }
1748  else if ( field == "rotation" )
1749  {
1750  ret = "0";
1751  }
1752  else if ( field == "rotationDistrib" )
1753  {
1754  ret = "6.283185307"; // 2*PI
1755  }
1756  else if ( field == "shaftLen" )
1757  {
1758  ret = "1.0e-6";
1759  }
1760  else if ( field == "shaftDia" )
1761  {
1762  ret = "0.2e-6";
1763  }
1764  else if ( field == "headLen" )
1765  {
1766  ret = "0.5e-6";
1767  }
1768  else if ( field == "headDia" )
1769  {
1770  ret = "0.5e-6";
1771  }
1772  else if ( field == "theta" )
1773  {
1774  ret = "0";
1775  }
1776  else if ( field == "phi" )
1777  {
1778  ret = "1.5707963268"; // PI/2
1779  }
1780  return ret;
1781 }
1782 
1784 static void addPos( unsigned int segIndex, unsigned int eIndex,
1785  double spacing, double minSpacing,
1786  double dendLength,
1787  vector< unsigned int >& seglistIndex,
1788  vector< unsigned int >& elistIndex,
1789  vector< double >& pos )
1790 {
1791  if ( minSpacing < spacing * 0.1 && minSpacing < 1e-7 )
1792  minSpacing = spacing * 0.1;
1793  if ( minSpacing > spacing * 0.5 )
1794  minSpacing = spacing * 0.5;
1795  unsigned int n = 1 + dendLength / minSpacing;
1796  double dx = dendLength / n;
1797  for( unsigned int i = 0; i < n; ++i )
1798  {
1799  // Use global RNG.
1800  if ( moose::mtrand() < dx / spacing )
1801  {
1802  seglistIndex.push_back( segIndex );
1803  elistIndex.push_back( eIndex );
1804  pos.push_back( i * dx + dx*0.5 );
1805  }
1806  }
1807 }
1808 
1809 /*
1810  * This version tries to put in Pos using simple increments from the
1811  * start of each compt. Multiple issues including inability to put
1812  * spines in small compartments, even if many of them.
1813  *
1814 static void addPos( unsigned int segIndex, unsigned int eIndex,
1815  double spacing, double spacingDistrib,
1816  double dendLength,
1817  vector< unsigned int >& seglistIndex,
1818  vector< unsigned int >& elistIndex,
1819  vector< double >& pos )
1820 {
1821  if ( spacingDistrib > 0.0 ) {
1822  double position = spacing * 0.5 +
1823  ( moose::mtrand() - 0.5 ) * spacingDistrib;
1824  while ( position < dendLength ) {
1825  seglistIndex.push_back( segIndex );
1826  elistIndex.push_back( eIndex );
1827  pos.push_back( position );
1828  position += spacing + ( moose::mtrand() - 0.5 ) * spacingDistrib;
1829  }
1830  } else {
1831  for ( double position = spacing * 0.5;
1832  position < dendLength; position += spacing ) {
1833  seglistIndex.push_back( segIndex );
1834  elistIndex.push_back( eIndex );
1835  pos.push_back( position );
1836  }
1837  }
1838 }
1839 */
1840 
1841 void Neuron::makeSpacingDistrib( const vector< ObjId >& elist,
1842  const vector< double >& val,
1843  vector< unsigned int >& seglistIndex,
1844  vector< unsigned int >& elistIndex,
1845  vector< double >& pos,
1846  const vector< string >& line ) const
1847 {
1848  string distribExpr = findArg( line, "spacingDistrib" );
1849  pos.resize( 0 );
1850  elistIndex.resize( 0 );
1851 
1852  try
1853  {
1854  nuParser parser( distribExpr );
1855 
1856  for ( unsigned int i = 0; i < elist.size(); ++i )
1857  {
1858  unsigned int j = i * nuParser::numVal;
1859  if ( val[ j + nuParser::EXPR ] > 0 )
1860  {
1861  double spacing = val[ j + nuParser::EXPR ];
1862  double spacingDistrib = parser.eval( val.begin() + j );
1863  if ( spacingDistrib > spacing || spacingDistrib < 0 )
1864  {
1865  cout << "Warning: Neuron::makeSpacingDistrib: " <<
1866  "0 < " << spacingDistrib << " < " << spacing <<
1867  " fails on " << elist[i].path() << ". Using 0.\n";
1868  spacingDistrib = 0.0;
1869  }
1870  map< Id, unsigned int>::const_iterator
1871  lookupDend = segIndex_.find( elist[i] );
1872  if ( lookupDend != segIndex_.end() )
1873  {
1874  double dendLength = segs_[lookupDend->second].length();
1875  addPos( lookupDend->second, i,
1876  spacing, spacingDistrib, dendLength,
1877  seglistIndex, elistIndex, pos );
1878  }
1879  }
1880  }
1881  }
1882  catch ( mu::Parser::exception_type& err )
1883  {
1884  cout << err.GetMsg() << endl;
1885  }
1886 }
1887 
1888 static void makeAngleDistrib ( const vector< ObjId >& elist,
1889  const vector< double >& val,
1890  vector< unsigned int >& elistIndex,
1891  vector< double >& theta,
1892  const vector< string >& line )
1893 {
1894  string angleExpr = findArg( line, "angle" );
1895  string angleDistribExpr = findArg( line, "angleDistrib" );
1896  // I won't bother with rotation and rotation distrb for now.
1897  // Easy to add, but on reflection they don't make sense.
1898  theta.clear();
1899  theta.resize( elistIndex.size(), 0.0 );
1900 
1901  try
1902  {
1903  nuParser angleParser( angleExpr );
1904  nuParser distribParser( angleDistribExpr );
1905  unsigned int lastIndex = ~0U;
1906  double angle = 0;
1907  double angleDistrib = 0;
1908  for ( unsigned int k = 0; k < elistIndex.size(); ++k )
1909  {
1910  unsigned int i = elistIndex[k];
1911  if ( i != lastIndex )
1912  {
1913  lastIndex = i;
1914  unsigned int j = i * nuParser::numVal;
1915  angle = angleParser.eval( val.begin() + j );
1916  angleDistrib = distribParser.eval( val.begin() + j);
1917  }
1918 
1919  // Use global RNG.
1920  if ( angleDistrib > 0 )
1921  theta[k] = angle + ( moose::mtrand() - 0.5 ) * angleDistrib;
1922  else
1923  theta[k] = angle;
1924  }
1925  }
1926  catch ( mu::Parser::exception_type& err )
1927  {
1928  cout << err.GetMsg() << endl;
1929  }
1930 }
1931 
1932 static void makeSizeDistrib ( const vector< ObjId >& elist,
1933  const vector< double >& val,
1934  vector< unsigned int >& elistIndex,
1935  vector< double >& size,
1936  const vector< string >& line )
1937 {
1938  string sizeExpr = findArg( line, "size" );
1939  string sizeDistribExpr = findArg( line, "sizeDistrib" );
1940  size.clear();
1941  size.resize( elistIndex.size(), 0.0 );
1942 
1943  try
1944  {
1945  nuParser sizeParser( sizeExpr );
1946  nuParser distribParser( sizeDistribExpr );
1947  unsigned int lastIndex = ~0U;
1948  double sz = 1.0;
1949  double sizeDistrib = 0;
1950  for ( unsigned int k = 0; k < elistIndex.size(); ++k )
1951  {
1952  unsigned int i = elistIndex[k];
1953  if ( i != lastIndex )
1954  {
1955  lastIndex = i;
1956  unsigned int j = i * nuParser::numVal;
1957  sz = sizeParser.eval( val.begin() + j );
1958  sizeDistrib = distribParser.eval( val.begin() + j);
1959  }
1960 
1961  // Use global RNG.
1962  if ( sizeDistrib > 0 )
1963  size[k] = sz + ( moose::mtrand() - 0.5 ) * sizeDistrib;
1964  else
1965  size[k] = sz;
1966  }
1967  }
1968  catch ( mu::Parser::exception_type& err )
1969  {
1970  cout << err.GetMsg() << endl;
1971  }
1972 }
1973 
1974 void Neuron::installSpines( const vector< ObjId >& elist,
1975  const vector< double >& val, const vector< string >& line )
1976 {
1977  Id spineProto( "/library/spine" );
1978 
1979  if ( spineProto == Id() )
1980  {
1981  cout << "Warning: Neuron::installSpines: Unable to find prototype spine: /library/spine\n";
1982  return;
1983  }
1984  // Look up elist index from pos index, since there may be many
1985  // spines on each segment.
1986  vector< unsigned int > elistIndex;
1987  vector< double > pos; // spacing of the new spines along compt.
1988  vector< double > theta; // Angle of spines
1989  vector< double > size; // Size scaling of spines
1990  pos.reserve( elist.size() );
1991  elistIndex.reserve( elist.size() );
1992 
1993  makeSpacingDistrib( elist, val,
1994  spineParentSegIndex_, elistIndex, pos, line);
1995  makeAngleDistrib( elist, val, elistIndex, theta, line );
1996  makeSizeDistrib( elist, val, elistIndex, size, line );
1997  for ( unsigned int k = 0; k < spineParentSegIndex_.size(); ++k )
1998  {
1999  unsigned int i = spineParentSegIndex_[k];
2000  Vec x, y, z;
2001  coordSystem( soma_, segId_[i], x, y, z );
2002  spines_.push_back(
2003  addSpine( segId_[i], spineProto, pos[k], theta[k],
2004  x, y, z, size[k], k )
2005  );
2006  }
2007  spineToMeshOrdering_.clear();
2008  spineToMeshOrdering_.resize( spines_.size(), 0 );
2009  spineStoich_.clear();
2010  spineStoich_.resize( spines_.size() );
2011  psdStoich_.clear();
2012  psdStoich_.resize( spines_.size() );
2013 
2015  allSpinesPerCompt_.clear();
2016  allSpinesPerCompt_.resize(segId_.size() );
2017  for ( unsigned int i = 0; i < spines_.size(); ++i )
2018  {
2019  assert( allSpinesPerCompt_.size() > spineParentSegIndex_[i] );
2020  vector< Id >& s = allSpinesPerCompt_[ spineParentSegIndex_[i] ];
2021  s.insert( s.end(), spines_[i].begin(), spines_[i].end() );
2022  }
2023 }
2025 // Interface funcs for spines
2027 
2028 Spine* Neuron::lookupSpine( unsigned int index )
2029 {
2030  return &spineEntry_;
2031 }
2032 
2033 void Neuron::setNumSpines( unsigned int num )
2034 {
2036  ;
2037 }
2038 
2039 unsigned int Neuron::getNumSpines() const
2040 {
2041  return spines_.size();
2042 }
2043 
2045 // Utility funcs for spines
2047 const vector< Id >& Neuron::spineIds( unsigned int index ) const
2048 {
2049  static vector< Id > fail;
2050  if ( index < spines_.size() )
2051  return spines_[index];
2052  return fail;
2053 }
2054 
2055 void Neuron::scaleBufAndRates( unsigned int spineNum,
2056  double lenScale, double diaScale ) const
2057 {
2058  double volScale = lenScale * diaScale * diaScale;
2059  if ( doubleEq( volScale, 1.0 ) )
2060  return;
2061  if ( spineStoich_.size() == 0 )
2062  // Perhaps no chem stuff in model, but user could have forgotten
2063  // to assign psd and spine meshes.
2064  return;
2065 
2066  if ( spineNum > spineStoich_.size() )
2067  {
2068  cout << "Error: Neuron::scaleBufAndRates: spineNum too big: " <<
2069  spineNum << " >= " << spineStoich_.size() << endl;
2070  return;
2071  }
2072  Id ss = spineStoich_[ spineNum ];
2073  if ( ss == Id() )
2074  {
2075  // The chem system for the spine may not have been defined.
2076  // Later figure out how to deal with cases where there is a psd
2077  // but no spine.
2078  return;
2079  }
2080  Id ps = psdStoich_[ spineNum ];
2081  if ( ps == Id() )
2082  {
2083  // The chem system for the spine may not have been defined.
2084  return;
2085  }
2086  SetGet2< unsigned int, double >::set( ss, "scaleBufsAndRates",
2087  spineToMeshOrdering_[spineNum], volScale );
2088  volScale = diaScale * diaScale;
2089  SetGet2< unsigned int, double >::set( ps, "scaleBufsAndRates",
2090  spineToMeshOrdering_[spineNum], volScale );
2091 }
2092 
2094 void Neuron::scaleShaftDiffusion( unsigned int spineNum,
2095  double len, double dia) const
2096 {
2097  double diffScale = dia * dia * 0.25 * PI / len;
2099  // Note that the buildNeuroMeshJunctions function is called
2100  // on the dendDsolve with the args smdsolve, pmdsolve.
2101  headDsolve_, "setDiffScale",
2102  spineToMeshOrdering_[ spineNum ], diffScale );
2103 }
2104 
2106 void Neuron::scaleHeadDiffusion( unsigned int spineNum,
2107  double len, double dia) const
2108 {
2109  double vol = len * dia * dia * PI * 0.25;
2110  // Note that the diffusion scale for the PSD uses half the length
2111  // of the head compartment. I'm explicitly putting this in below.
2112  double diffScale = dia * dia * 0.25 * PI / (len/2.0);
2113  unsigned int meshIndex = spineToMeshOrdering_[ spineNum ];
2114  Id headCompt = Field< Id >::get( headDsolve_, "compartment" );
2115  LookupField< unsigned int, double >::set( headCompt, "oneVoxelVolume",
2116  meshIndex, vol );
2117  Id psdCompt = Field< Id >::get( psdDsolve_, "compartment" );
2118  double thick = Field< double >::get( psdCompt, "thickness" );
2119  double psdVol = thick * dia * dia * PI * 0.25;
2120  LookupField< unsigned int, double >::set( psdCompt, "oneVoxelVolume",
2121  meshIndex, psdVol );
2123  headDsolve_, "setDiffVol1", meshIndex, vol );
2125  psdDsolve_, "setDiffVol2", meshIndex, vol );
2127  psdDsolve_, "setDiffVol1", meshIndex, psdVol );
2129  psdDsolve_, "setDiffScale", meshIndex, diffScale );
2130 }
unsigned int getNumCompartments() const
Definition: Neuron.cpp:904
Id soma_
Definition: Neuron.h:119
int wildcardFind(const string &path, vector< ObjId > &ret)
Definition: Wildcard.cpp:169
Id id() const
Definition: Eref.cpp:62
vector< unsigned int > spineToMeshOrdering_
looks up spine/psd mesh index from FieldIndex of selected spine.
Definition: Neuron.h:140
void setPassiveDistribution(const Eref &e, vector< string > v)
Definition: Neuron.cpp:1163
double maxL
Definition: Neuron.cpp:96
double Em_
Definition: Neuron.h:113
char * data() const
Definition: Eref.cpp:41
static double H(double arg)
Definition: Neuron.cpp:66
double y
Definition: Neuron.cpp:98
static ObjId parent(const Eref &e)
Definition: Neutral.cpp:701
double a0() const
Definition: Vec.h:34
Definition: Neuron.h:18
static void setMechParams(const vector< ObjId > &mech, const vector< ObjId > &elist, const vector< double > &val, const string &field, const string &expr)
Definition: Neuron.cpp:784
static bool set(const ObjId &dest, const string &field, L index, A arg)
Definition: SetGet.h:467
void setCM(double v)
Definition: Neuron.cpp:838
double dia
Definition: Neuron.cpp:93
void scaleHeadDiffusion(unsigned int spineNum, double len, double dia) const
Scale the diffusion parameters due to a change in the head dimensions.
Definition: Neuron.cpp:2106
double RM_
Definition: Neuron.h:110
static void fillSegments(vector< SwcSegment > &segs, const map< Id, unsigned int > &segIndex, const vector< Id > &kids)
Definition: Neuron.cpp:1275
static void assignParam(Id obj, const string &field, double val, double len, double dia)
Definition: Neuron.cpp:680
double compartmentLengthInLambdas_
Definition: Neuron.h:121
void setSpineAndPsdDsolve(Id spineDsolve, Id psdDsolve)
Definition: Neuron.cpp:1462
Element * element() const
Synonym for Id::operator()()
Definition: Id.cpp:113
void setRA(double v)
Definition: Neuron.cpp:826
static void doClassSpecificMessaging(Shell *shell, Id obj, ObjId compt)
Definition: Neuron.cpp:619
bool parseDistrib(vector< vector< string > > &lines, const vector< string > &distrib)
Definition: Neuron.cpp:587
Neuron()
Definition: Neuron.cpp:542
string sourceFile_
Definition: Neuron.h:120
void makeSpacingDistrib(const vector< ObjId > &elist, const vector< double > &val, vector< unsigned int > &seglistIndex, vector< unsigned int > &elistIndex, vector< double > &pos, const vector< string > &line) const
Definition: Neuron.cpp:1841
vector< double > getPathDistFromSoma() const
Definition: Neuron.cpp:921
bool bad() const
Definition: ObjId.cpp:18
std::string path(const std::string &separator="/") const
Definition: Id.cpp:76
unsigned int value() const
Definition: Id.cpp:197
vector< string > channelDistribution_
Definition: Neuron.h:122
double oldVal
Definition: Neuron.cpp:100
Definition: Dinfo.h:60
unsigned int getNumBranches() const
Definition: Neuron.cpp:916
double phi_
Definition: Neuron.h:115
vector< string > passiveDistribution_
Definition: Neuron.h:123
void installSpines(const vector< ObjId > &elist, const vector< double > &val, const vector< string > &line)
Definition: Neuron.cpp:1974
Definition: SetGet.h:236
vector< ObjId > getExprElist(const Eref &e, string line) const
Definition: Neuron.cpp:959
Id id
Definition: ObjId.h:98
unsigned int dataIndex() const
Definition: Eref.h:50
static const Cinfo * find(const std::string &name)
Definition: Cinfo.cpp:200
void buildElist(const Eref &e, const vector< string > &line, vector< ObjId > &elist, vector< double > &val)
Definition: Neuron.cpp:1116
Id doCopy(Id orig, ObjId newParent, string newName, unsigned int n, bool toGlobal, bool copyExtMsgs)
Returns the Id of the root of the copied tree upon success.
Definition: ShellCopy.cpp:16
double x
Definition: Neuron.cpp:97
const double FaradayConst
Definition: consts.cpp:17
static Id child(const Eref &e, const string &name)
Definition: Neutral.cpp:665
double RA_
Definition: Neuron.h:111
void setSourceFile(string v)
Definition: Neuron.cpp:883
double maxL_
Definition: Neuron.h:118
double a2() const
Definition: Vec.h:40
Spine * lookupSpine(unsigned int index)
Definition: Neuron.cpp:2028
vector< vector< Id > > allSpinesPerCompt_
Id of each compt in each spine.
Definition: Neuron.h:133
Definition: ObjId.h:20
void evalExprForElist(const vector< ObjId > &elist, const string &expn, vector< double > &val) const
Definition: Neuron.cpp:1478
Eref eref() const
Definition: Id.cpp:125
Id headDsolve_
Definition: Neuron.h:142
static void children(const Eref &e, vector< Id > &ret)
Definition: Neutral.cpp:342
static bool set(const ObjId &dest, const string &field, A arg)
Definition: SetGet.h:245
static void traverseCumulativeDistance(SwcSegment &self, vector< SwcSegment > &segs, const vector< Id > &lookupId, double len, double L, double pSoma, double eSoma)
Recursive function to fill in cumulative distances from soma.
Definition: Neuron.cpp:1311
double eval(vector< double >::const_iterator arg0)
Definition: Neuron.cpp:71
map< Id, unsigned int > segIndex_
Map to look up Seg index from Id of associated compt.
Definition: Neuron.h:127
static void reorientSpine(vector< Id > &spineCompts, vector< Vec > &coords, Vec &parentPos, double pos, double angle, Vec &x, Vec &y, Vec &z)
Definition: Neuron.cpp:1583
static bool buildFromProto(const string &name, const vector< ObjId > &elist, const vector< double > &val, vector< ObjId > &mech)
Definition: Neuron.cpp:647
static const Cinfo * initCinfo()
Definition: Neuron.cpp:106
ObjId getCwe() const
Definition: Shell.cpp:615
Vec crossProduct(const Vec &other) const
Definition: Vec.cpp:26
Definition: OpFunc.h:40
vector< Id > psdStoich_
Id of stoich associated with each PSD. Typically all the same.
Definition: Neuron.h:138
Spine spineEntry_
Id of the Dsolve for the PSD compt.
Definition: Neuron.h:150
const vector< Id > & spineIds(unsigned int index) const
Definition: Neuron.cpp:2047
vector< string > getChannelDistribution(const Eref &e) const
Definition: Neuron.cpp:1158
double p
Definition: Neuron.cpp:89
double getRM() const
Definition: Neuron.cpp:821
static Id getComptParent(Id id)
Definition: Neuron.cpp:1215
string findArg(const vector< string > &line, const string &field)
Definition: Neuron.cpp:1716
bool doubleEq(double x, double y)
Definition: doubleEq.cpp:16
Definition: Vec.h:13
double theta_
Definition: Neuron.h:114
double getCompartmentLengthInLambdas() const
Definition: Neuron.cpp:899
double getPhi() const
Definition: Neuron.cpp:877
void setPhi(double v)
Definition: Neuron.cpp:872
static void makeSizeDistrib(const vector< ObjId > &elist, const vector< double > &val, vector< unsigned int > &elistIndex, vector< double > &size, const vector< string > &line)
Definition: Neuron.cpp:1932
double getRA() const
Definition: Neuron.cpp:833
void setSpineAndPsdMesh(Id spineMesh, Id psdMesh)
Fills up vector of segments. First entry is soma.
Definition: Neuron.cpp:1410
valArgs
Defines the order of arguments in the val array.
Definition: Neuron.cpp:62
double getEm() const
Definition: Neuron.cpp:855
double getCM() const
Definition: Neuron.cpp:845
double maxP
Definition: Neuron.cpp:94
static const Cinfo * initCinfo()
Definition: Spine.cpp:17
double maxG_
Definition: Neuron.h:117
string path() const
Definition: ObjId.cpp:119
static double coordSystem(Id soma, Id dend, Vec &x, Vec &y, Vec &z)
Definition: Neuron.cpp:1546
Definition: EpFunc.h:49
void scaleShaftDiffusion(unsigned int spineNum, double len, double dia) const
Scale the diffusion parameters due to a change in the shaft dimensions.
Definition: Neuron.cpp:2094
double length() const
Definition: Vec.cpp:18
double maxP_
Definition: Neuron.h:116
vector< ObjId > getSpinesFromExpression(const Eref &e, string line) const
Definition: Neuron.cpp:1009
void setTheta(double v)
Definition: Neuron.cpp:861
bool useOldVal
Definition: Neuron.cpp:101
string getSourceFile() const
Definition: Neuron.cpp:889
bool matchBeforeBrace(ObjId id, const string &wild)
Definition: Wildcard.cpp:432
ObjId objId() const
Definition: Eref.cpp:57
Definition: Eref.h:26
bool isA(const string &ancestor) const
Definition: Cinfo.cpp:280
vector< vector< Id > > spines_
Definition: Neuron.h:130
nuParser(const string &expr)
Definition: Neuron.cpp:27
vector< double > getExprVal(const Eref &e, string line) const
Definition: Neuron.cpp:991
double distance(const SwcSegment &other) const
Definition: SwcSegment.h:87
const Cinfo * cinfo() const
Definition: Element.cpp:66
double z
Definition: Neuron.cpp:99
double g
Definition: Neuron.cpp:90
vector< Id > segId_
Definition: Neuron.h:152
static void addChannelMessage(Id chan)
Definition: ReadCell.cpp:985
vector< string > getSpineDistribution(const Eref &e) const
Definition: Neuron.cpp:1205
vector< string > getPassiveDistribution(const Eref &e) const
Definition: Neuron.cpp:1183
double getTheta() const
Definition: Neuron.cpp:866
ObjId getParentCompartmentOfSpine(const Eref &e, ObjId compt) const
Definition: Neuron.cpp:1066
void setSpineDistribution(const Eref &e, vector< string > v)
Definition: Neuron.cpp:1188
void setChannelDistribution(const Eref &e, vector< string > v)
Definition: Neuron.cpp:1132
vector< SwcBranch > branches_
Definition: Neuron.h:154
static char name[]
Definition: mfield.cpp:401
void setCwe(ObjId cwe)
Definition: Shell.cpp:610
vector< ObjId > getSpineIdsFromCompartmentIds(const Eref &e, vector< ObjId > compt) const
Definition: Neuron.cpp:1079
double len
Definition: Neuron.cpp:92
ObjId doAddMsg(const string &msgType, ObjId src, const string &srcField, ObjId dest, const string &destField)
Definition: Shell.cpp:269
Id fillSegIndex(const vector< Id > &kids, map< Id, unsigned int > &segIndex)
Definition: Neuron.cpp:1241
vector< ObjId > getCompartments() const
Definition: Neuron.cpp:945
void setCompartmentLengthInLambdas(double v)
Definition: Neuron.cpp:895
static void makeAngleDistrib(const vector< ObjId > &elist, const vector< double > &val, vector< unsigned int > &elistIndex, vector< double > &theta, const vector< string > &line)
Definition: Neuron.cpp:1888
vector< unsigned int > spineParentSegIndex_
Look up seg index of parent compartment, from index of spine.
Definition: Neuron.h:129
Id psdDsolve_
Id of the Dsolve for the head compt.
Definition: Neuron.h:143
const double PI
Definition: consts.cpp:12
bool doDelete(ObjId oid)
Definition: Shell.cpp:259
double mtrand(void)
Generate a random double between 0 and 1.
Definition: global.cpp:97
void setNumSpines(unsigned int num)
Definition: Neuron.cpp:2033
Definition: Id.h:17
static void setCompartmentParams(const vector< ObjId > &elist, const vector< double > &val, const string &field, const string &expr)
Definition: Neuron.cpp:758
void buildSegmentTree(const Eref &e)
Fills up vector of segments. First entry is soma.
Definition: Neuron.cpp:1362
unsigned int getNumSpines() const
Definition: Neuron.cpp:2039
static void assignSingleCompartmentParams(ObjId compt, double val, const string &field, double len, double dia)
Definition: Neuron.cpp:719
static A get(const ObjId &dest, const string &field)
Definition: SetGet.h:284
static const Cinfo * initCinfo()
Definition: Neutral.cpp:16
void updateSegmentLengths()
Definition: Neuron.cpp:1333
double a1() const
Definition: Vec.h:37
double maxG
Definition: Neuron.cpp:95
static void addPos(unsigned int segIndex, unsigned int eIndex, double spacing, double minSpacing, double dendLength, vector< unsigned int > &seglistIndex, vector< unsigned int > &elistIndex, vector< double > &pos)
Add entries into the pos vector for a given compartment i.
Definition: Neuron.cpp:1784
vector< ObjId > getSpinesOnCompartment(const Eref &e, ObjId compt) const
Definition: Neuron.cpp:1050
vector< Id > spineStoich_
Id of stoich associated with each spine. Typically all the same.
Definition: Neuron.h:136
#define EPSILON
Definition: MatrixOps.h:28
static vector< Id > addSpine(Id parentCompt, Id spineProto, double pos, double angle, Vec &x, Vec &y, Vec &z, double size, unsigned int k)
Definition: Neuron.cpp:1649
void setRM(double v)
Definition: Neuron.cpp:814
const string & getName() const
Definition: Element.cpp:56
void scaleBufAndRates(unsigned int spineNum, double lenScale, double diaScale) const
Definition: Neuron.cpp:2055
Definition: Spine.h:24
double CM_
Definition: Neuron.h:112
double L
Definition: Neuron.cpp:91
static const unsigned int numVal
Definition: Neuron.cpp:88
vector< SwcSegment > segs_
Id of compartment in each Seg entry, below.
Definition: Neuron.h:153
static const Cinfo * neuronCinfo
Definition: Neuron.cpp:539
Definition: Cinfo.h:18
static char path[]
Definition: mfield.cpp:403
vector< string > spineDistribution_
Definition: Neuron.h:124
Definition: Shell.h:43
const Finfo * findFinfo(const string &name) const
Definition: Cinfo.cpp:224
void setEm(double v)
Definition: Neuron.cpp:851
vector< double > getGeomDistFromSoma() const
Definition: Neuron.cpp:929
Definition: Finfo.h:12
static bool set(const ObjId &dest, const string &field, A1 arg1, A2 arg2)
Definition: SetGet.h:365
void doMove(Id orig, ObjId newParent)
Definition: Shell.cpp:390
vector< double > getElecDistFromSoma() const
Definition: Neuron.cpp:937