longitudinal_diffusion caching?

NMODL and the Channel Builder.
Post Reply
ramcdougal
Posts: 160
Joined: Fri Nov 28, 2008 3:38 pm
Location: Yale School of Public Health

longitudinal_diffusion caching?

Post by ramcdougal » Fri Nov 28, 2008 4:01 pm

I was experimenting with longitudinal_diffusion and the results were not quite as I expected: I'd create a section of length 10, put some stuff on the left side, and then it would diffuse across a certain rate. If now I change the length of the section and rerun it, my substance diffuses across the exact same percentage of the section. I have only been able to get around this by exiting NEURON and rerunning my code with the new length as my initial length. Am I doing something wrong, or does longitudinal_diffusion keep track of the lengths when it was first run, and if so, how do I delete this cached information? Thanks!

A simple example of a code that demonstrates this behavior follows:

difftest.hoc:

Code: Select all

// initial setup
{
 NUMSEGS=10
 LENGTH=10
 PRINTEVERY=100
 create stick
}

proc go() {
 access stick

 // specify L, nseg
 nseg=NUMSEGS
 L=LENGTH

 // insert diffusion
 insert diff

 // initial substance in left only
 finitialize()
 z_diff(0)=9

 // run it
 {
  for i=1, 10 {
   
   // print from interior of stick
   for(x) {
    if (abs(x-.5)!=.5) printf("%.4f ", z_diff(x))
   }
   printf("\n")
   
   for j=1, PRINTEVERY {fadvance()}
  }
 }
}

print "Set LENGTH then type 'go()'"
where diffusion was accomplished via diff.mod:

Code: Select all

NEURON {
 SUFFIX diff
}

BREAKPOINT {
 SOLVE state METHOD sparse
}

STATE {
 z   (1)
}

KINETIC state {
 COMPARTMENT 1 {z}
 LONGITUDINAL_DIFFUSION 1 {z}
 ~z << (0)
}

ramcdougal
Posts: 160
Joined: Fri Nov 28, 2008 3:38 pm
Location: Yale School of Public Health

Re: longitudinal_diffusion caching?

Post by ramcdougal » Fri Nov 28, 2008 4:30 pm

Upon further reflection, I realize that I could use delete_section to remove the sections and start over from scratch, but I would prefer to preserve all the geometry, biophysics, etc...

ted
Site Admin
Posts: 5624
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: longitudinal_diffusion caching?

Post by ted » Sun Nov 30, 2008 8:28 pm

Thanks for posting your query--you discovered a bug that needed to be fixed. Changes in the model specification are supposed to be detected during initialization, and are supposed to produce corresponding changes in the Jacobian; this was not occurring for the part of the Jacobian that handles longitudinal diffusion, in response to changes in section geometry.

This bug has been fixed in the latest source code that is downloadable from the mercurial repository, and the fix will be included in future alpha and standard release installers. If you rely on one of the installers instead of compiling from source code, there is a workaround:
every time you change L (or section diameter), also do the following:
nseg*=3
nseg/=3
Then it will be safe to run a new simulation.

Explanation:
Tripling nseg forces the necessary change in the Jacobian, without affecting the locations of point processes.
Dividing nseg by 3 restores the spatial grid to its original resolution (and the Jacobian to its previous size), while preserving the changes that were required by the alteration of section geometry.
Alternatively, you might try
area(0.5)
which should also force a recalculation of the Jacobian's coefficients.

An additional comment: your mod file lacks an INITIAL block, is casual about units and does not properly take compartment size into consideration. It's a good idea to have an INITIAL block, not only for the sake of conceptual clarity, but also because it is best not to leave initialization to chance. Carelessness about units precludes the use of modlunit to detect syntax errors, and invites erroneous results caused by units inconsistencies. Compartment size is always important in accumulation mechanisms.

Here is a mod file that illustrates correct usage:

Code: Select all

NEURON {
  SUFFIX diff
}

UNITS {
  PI = (pi) (1)
  (molar) = (1/liter)
  (mM) = (millimolar)
  (um) = (micron)
}

ASSIGNED {
  diam (um)
}

PARAMETER {
  : since z is a STATE, the name "Dz" is automatically created
  : and means dz/dt
  : therefore must use something else as the name of the diffusion constant
  DZ = 1 (um2/ms)
}

BREAKPOINT {
  SOLVE state METHOD sparse
}

STATE {
  z   (mM)
}

INITIAL {
  z = 0
}

KINETIC state {
  COMPARTMENT diam*diam*PI/4 {z}
  LONGITUDINAL_DIFFUSION DZ*diam*diam*PI/4 {z}
  ~z << (0)
}

Post Reply