A Simplifed Introduction to NEURON Simulator—（私的）NEURON 事始め—
Keiji Imoto
Department of Information Physiology
National Institute for Physiological Sciences
Okazaki 444-8787, Japan
13-March-2009

11-June-2010: correction of bugs in n12.hoc
12-April-2010: minor changes
06-July-2012: minor update

目次
はじめに

1

1

1.1

説明書の対象者. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1

1.2

NEURON シミュレータの特徴 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1

シミュレーションの基本

32.1

膜電位 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3

2.2

イオンチャネル. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

4

2.3

微分法的式の計算方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

4

2.4

C 言語 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

4

hoc ファイルと oc インタープリタ

4

3.1

インタープリタとしての oc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

4

3.2

Section . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

6

3.3

Connecting sections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

9

3.4

Point Process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

10

3.5

クラス . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

13

3.6

NetCon、NetStim . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

13

3.7

Voltage clamp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

16Morphology

24

4.1

section . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

24

4.2

geometory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

25

4.3

segment の長さ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

26

Spikes38

5.1

NetCon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

38

5.2

Raster Plot の描き方 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

38

NMODL

40

6.1

Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

40

6.2

例：常微分方程式を解いてみる . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

41

6.3

IntervalFire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

43

6.4

Synaptic transmission . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

46

6.5

Synaptic plasticity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

48

6.6

NMDA receptor channel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

50

NEURON の内部

53

7.1

初期化 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

53

7.2

Integration の方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

53

2

3

4

5

6

7

7.3

Graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

53

インストールの仕方

54

A.1

Windows の場合 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

54

A.2

Mac OS の場合 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

54

A.3

Linux の場合 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

55

A.4

計算速度 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

55

hoc ファイル用のテキストエディタ

55

B.1

Emacs 系テキストエディタ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

55

B.2

Notepad++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

56

B.3

Coteditor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

56

References

56

付録 A

付録 B

付録 C

1 はじめに
Ted Carnevale と Michael Hines により開発され、現在も開発され続けている NEURON シミュレータは、
もっともポピュラーな神経細胞、神経ネットワークのシミュレータである。10 年以上の歴史があり、多くの論文でも利用されている。基本的に NEURON は、神経細胞をコンパートメントに分け、コンパートメント iの電位変化を、微分方程式

dVi
1 ∑
=−
Ii,j
dt
Ci j

で表し、これらを数値的に解くものである。神経細胞の形態を再現しようとするとコンパートメントの数が多
くなり、またそれぞれのコンパートメントに含まれるチャネルのキネティックスの定義にもよく微分方程式が用いられるため、多数の微分方程式を並行して計算することが必要となる。NEURON はそのような機能を備えたソフトウェアである。NEURON は現在もすこしずつ機能が付け足されてきており、多数の（モデル）神経細胞からなるネットワークのシミュレーションも可能である。
このように NEURON は高度な性能を持つソフトウェアであるが、2006 年に The NEURON Book

(Canbridge University Press) が出版されるまで、まとまった入門書がなかったこともあり、なかなか取っ付
きにくいというのが一般的な印象だろうと思われる。筆者自身、何度か NEURON をコンピュータにインストールし、チュートリアルなどを試してみたが、結局使えるほどの理解を得るには至らなかった。問題点を考え直してみたところ、少なくとも個人的には、プログラムの中核である oc インタープリタをどう使うのかがわからない、ということが初歩のチュートリアル以上に進めない理由なのではないか、と思うようになった。
この（私的）事始めでは、GUI 部分を出来るだけ利用せず、NEURON の根幹である oc インタープリタを動かすための hoc ファイルの理解を中心に説明を試みた。

1.1 説明書の対象者
この説明書は、ある程度プログラミングに経験のある人をターゲットにしている。例題を多く含めたので、初心者でも書いてある内容を再現できるが、C/C++ 言語並びに数値計算についての基本的な知識があれば、更に発展した NEURON の使用ができると期待している。

1.2 NEURON シミュレータの特徴
NEURON シミュレータの特徴として 3 つの点があげられる。
1. oc は NEURON の根幹となるインタープリタであり、非常に数多くの連立微分方程式の数値解を求めることができる。

2. mknrnmodl（システムによっては mknrndll）は、イオンチャネル等のコンポーネントを新たに作製し、プログラムに組み込むことができる。

3. template 機能を用いて、object 指向的なプログラムが可能である。
2 は微分方程式等の詳細を記載した mod ファイルをシステムに組込む操作である。初歩的な機能要素は既定のシステムに備わっているので、備わっていない機能要素を加える場合に必要。
また付属の機能として、次のようなものがある。

1• CellBuilder: 神経細胞の複雑な形態を、円柱で近似されるコンパートメント（section と呼ばれている）のつながりとしてプログラム化する。

• NetBuilder: 神経細胞間の情報伝達を event の伝達として処理するようにプログラム化する。
これらは GUI を主体とした部分であるが、複雑な構造やネットワークを作っていくには、むしろ古典的なテ
キストファイルを用いる方法の方が適している場合もある。

NEURON は（一旦学べば）比較的手軽に使用できるシミュレーション環境である。特に有用な課題は、
1. 複数のコンパートメント（section）からなる神経細胞での、イオンチャネル機能の検討。特にイオンチャネル間の相互作用やクランプエラー等の測定誤差の理解に有用。

2. 細胞集団におけるスパイクの同期性等におよぼす要素の検討。但し、この種類のシミュレーションをパ
ソコンレベルのコンピュータで行なう場合には、単純化したモデルニューロンを使用する必要がある。

.

なお、文中の
はコメント、は注意すべき事項を示す（dangerous bend 危険な曲がり道）。

2

2 シミュレーションの基本
2.1 膜電位NEURON シミュレータは、神経細胞の電位変化のシミュレーションを得意とするプログラムである。細胞をコンデンサと考え、それに蓄えられる電荷の量により膜電位が生じている、というのが基本的な考え方である。蓄えられている電荷量を Q、静電容量（キャパシタンス）を C とすると、電位 V との関係は、

Q = CVで表される。C を定数として扱い、この式の両辺を時間 t で微分すると、

dQ
dV
=C
dt
dt
となる。左辺は、細胞に出入りする電荷量の時間的変化量、すなわち電流 I である。電気生理学の習わしとして、細胞内に流れる電流を負の値として示すので、

I=−

dQ
dt

である。従って、電流 I と電位 V の関係は、

dV
1
=− I
dt
C
V (t) = V (0) −1
C∫ τ =tIdττ =0となる。この式は、細胞の膜電位の初期値と、細胞に出入りする電流がわかれば、膜電位の時間的変化は計算できることを示している。
神経細胞は複雑な形をしている。特樹状突起は長く伸びており、神経細胞を単なる球体のように扱うことは出来ない。このため NEURON では神経細胞を球体、円柱体などの集まりとして考え、それぞれのコンパート
メントについて電位の微分方程式を解くという手法をとっている。またそれぞれの構成コンパートメントに入出する電流にはさまざまな種類の電流が含まれる。電位依存性イオンチャネルを介する電流、神経伝達物質依存性イオンチャネルを介する電流（シナプス電流がこれに相当する）、leak 電流（常に開いているイオンチャ
ネルを流れる電流）、近接のコンパートメントとの電流等が考えられる。神経細胞には多種類のイオンチャネルが存在しているので、電流の種類数はかなりの数になると予想される。しかし現実には、それぞれのイオン
チャネルの分布などの情報はほとんどないことから、数種類のイオンチャネルでシミュレーションを行うことが普通である。i コンパートメント、j 電流の考えを含めると、冒頭で示した式となる。

1 ∑
dVi
=−
Ii,j
dt
Ci j

3

2.2 イオンチャネル
2.3 微分法的式の計算方法
2.4 C 言語

3 hoc ファイルと oc インタープリタ
3.1 インタープリタとしての oc
oc は、Windows/Cygwin の場合、nrngui のアイコンをクリックするか、コマンドプロンプトで neuron とコマンド入力することで起動できる。Mac OS の場合、nrngui のアイコンをクリックするか、コマンドから開く場合は、open -a nrngui で起動できる（ソースコードからコンパイルした場合は、異なる）。いずれの環境の場合も、nrngui の場合は、nrngui.hoc がロードされ実行されている。Mac OS でコンパイルした場合やLinux の場合は、PATH をしかるべく設定すれば、nrniv で起動できるはずである。
oc は、一行一行入力することも可能であるが、通常 hoc ファイルを読み込ませて作業を行う。その場合には、neuron hoc file name -とする。最後の’-’ を付けると、hoc ファイルの実行を終えても oc は終了しない。

hoc プログラム上の要点。
• 数値変数は宣言を必要としない。
• 数値変数は全て double（8 バイト実数）。整数として用いられる場合には truncate される。
• C 言語のように double i というように宣言すると、エラーとなる• 配列の場合は数値でも double の宣言必要。配列要素の数は定数でなくてもよい。
• 数値変数を含め、変数は通常グローバル変数 global として扱われる。
• 数値変数を関数内に限局するには local の宣言が必要。
• 数値以外の変数には、色々なオブジェクトのレファレンス、文字列等があり、objref、strdef 等の宣言を必要とする。*1• オブジェクトのレファレンスを関数内で局所的に使用するには、objref の代わりに localobj を使用する。（strdef の local 版はないようだ。）• ポインターを使用することができる。
• シミュレーションの要素としては、コンパートメントである section、そこで局所的に起きる現象 point
process がある。section は global として扱われるようである。point process は単独で使用することは出来ず、ある section の point process として使用される。概念的な point process を使用する場合は、
形式的に section を定義して用いる。

• 関数は、func()、proc() で定義される。func() は数値を返すのに対して、proc() は返り値なし。引数
は、数値の場合$1、文字列の場合$s1、objref の場合$o1 として表される。func()、proc() の括弧の中には引数を書かない。

• main() は存在しない。各種の宣言（変数、関数、クラス）以外の部分が順番に実行される。
• 組込み関数がある（表 1）。例えば、printf() は、標準出力に文字列を出力する。
*1 クラスとは、鋳型もしくはひな形のことを指す。ひな形を元に実際に作られたもの（ここでは変数）がオブジェクト（インスタン

スとも言う）である。

4• プログラムの流れを制御するステートメントとして、if、else、break、for、while 等が使用できる。
• forall、forsec 等が便利。
//-----------------------------------------------// n01.hoc:

a C-like hoc program

strdef s
s = "Hello, World!"
for t = 0, 3 {printf("%d %s\n", t,s)}//------------------------------------------------. //で始まる行はコメント行。//が行の途中で来れば、それ以降がコメント。また C 言語と同様に、/**/を使用できる。文字列の変数を使用する場合には、変数の宣言として strdef が必要。for にはいく通りかの使用方法があるが、この使い方が最もよく用いられている様である。この場合、後の数（ここでは 3）が含まれていることに注意。printf は、C 言語の場合とほぼ同じ。変数が double の場合でも、%f でよく %lf とする必要はない様である。
ファイルへの出力の場合は、次のように行なう。

//-----------------------------------------------// n02.hoc:

a C-like hoc programwith text file output

strdef s
s = "Hello, World!"
wopen("a.txt")// open for write

for t = 0, 3 {fprint("%d %s\n", t, s)}
wopen()//------------------------------------------------.

ファイル IO（Input-Output）には、テキストファイルが用いられることが多い。書き込み用にファイルを開く場合は、wopen(filename) を用い、閉じる場合は引数なしで wopen() を使用する。C 言語で用いられる fprintf() ではなく fprint() であることに注意。ファイル IO には、File クラスを用いる方法もあり、この場合はバイナリの読み書きがサポートされている。
実際に数値をファイルに書き出し、それをグラフを描くプログラム gc を用いてプロットしてみる。gc はホームメイドのプログラムで、コマンドで使用可。Windows 版と MacOS 版を用意してある。MacOS 版はバイナリファイルのみ使用可。

//-----------------------------------------------// n03.hoc:

drowing a small graphwopen("a.txt")// open a file for "write"

tstop = 200
5for t=0, tstop {fprint("%f %f\n", t, sin(0.1*t))}wopen()// close the output file

WinExec("gc a.txt")//------------------------------------------------.

プログラム中からコマンドを使ったり、他のプログラムを起動するには、system() を利用する。

Windows/Cygwin 環境では、WinExcec() を使用する。
binary ファイルの場合は下記のようになる。binary を用いる利点は、ファイルサイズがコンパクトで、読み書きが速いことであるが、テキストエディタで内容がわからない欠点がある。

//-----------------------------------------------// n04.hoc:

drowing a small graph (binary file version)

objref fp
fp = new File()
fp.wopen("a.dat")
double a[2]tstop = 200
for t=0, tstop {a[0] = ta[1] = sin(0.1 * t)
fp.vwrite(2, &a)}
fp.close()
WinExec("gc a.dat")//------------------------------------------------. Fileクラスを利用している。クラスを利用してオブジェクトを作成するには、まず objref aObject と宣言をして、aObject = new Class() という構文でオブジェクトを作成する。入力にファイルを開く場合は.ropen()、出力にファイルを開く場合は.wopen() を用いる。binary ファイルの読み書きには、.vread()、.vwrite() を用いる。また、C 言語でおなじみの.seek()、.tell() も利用できる。

3.2 Section
いよいよ神経細胞のコンパートメント（section）を定義する。これには create というステートメントが用いられる。内部的にはコンパートメントのオブジェクトが作成されるのだと推測される。先ず初めに 1 コンパートメントを作成し、そこに Hodgkin-Huxley タイプの Na+ チャネル、K+ チャネル、leak チャネルのパッケージである hh を挿入してみる。

//-----------------------------------------------6

//

n05.hoc:

a simple hh cell

create soma
soma insert hh
tstop = 200
dt = 0.01
v_init = -65
wopen("a.txt")
finitialize(v_init)
fcurrent()
while(t<tstop){
fadvance()
fprint("%f %f\n", t, soma.v(0.5))}
wopen()
WinExec("gc a.txt &")//------------------------------------------------. hoc

ファイルでの操作は、いずれかの section に対して行なう場合が多い。一般的に、section statementという形式が用いられる。finitialize()、fcurrent() は、シミュレーション計算の初期化を行なう。fad-vance() は、1 ステップ計算を行なう。global 変数である時間 t は、fadvance() により dt（これも global変数）だけ増加されるので、t を増加させる命令は不必要である。
出力ファイルを binary file にしたバージョン。

//-----------------------------------------------// n06.hoc:

a simple hh cell (binary version)

create soma
soma insert hh
tstop = 200
dt = 0.01
v_init = -65
objref fp
fp = new File()
fp.wopen("a.dat")
double a[2]finitialize(v_init)
fcurrent()

7

while(t<tstop){
fadvance()a[0] = ta[1] = soma.v(0.5)
fp.vwrite(2,&a)}fp.close()
WinExec("gc a.dat")//-----------------------------------------------n05.hoc と n06.hoc では、soma の電位 v をプロットしているが、予想通り何もおきない。
これではつまらないし、うまくプログラムが動作しているかもわからないため、leak 電流の性質を変更してみる。n05.hoc と n06.hoc では、soma や hh のパラメータは、既定値を用いており、hh の leak 電流の平衡
電位は、default の場合-54.3 mV であるが、この値を-30 mV に変更してみる。細胞はこの leak 電流のために脱分極し、Na+ チャネルの閾値に達して action potential を発生し、K+ チャネルにより再分極する。まさしく HH モデルの世界！なお hh の詳細は hh.mod で定義されている。

//-----------------------------------------------// n07.hoc:

a simple hh cell, with increased leakcreate soma
soma insert hhsoma el_hh = -30// added

tstop = 200
dt = 0.01
v_init = -65
objref fp
fp = new File()
fp.wopen("a.dat")
double a[2]finitialize(v_init)
fcurrent()
while(t<tstop){
fadvance()a[0] = ta[1] = soma.v(0.5)
fp.vwrite(2,&a)}fp.close()
WinExec("gc a.dat")
8

40
20
0
-20
-40
-60

0

50

100

150

200

Fig.1 n07.hoc: a simple hh-type neuron//------------------------------------------------


ここではシステムが動くことを確認するために hh.mod を用いているが、hh.mod は squid axon のモデルであり、6.3 ℃という低温での実験に合わせたパラメータを用いている。温度は global 変数 celsius で設定できる。celsius は default で 6.3 に設定されているようである。温度は Q10 を通してチャネル等のキ
ネティックスに反映される。n07.hoc の場合、celsius = 37 とすると、action potential は発生しなくなってしまう。なお、soma gnabar hh *= 3 として、Na チャネルの density を 3 倍に増加させると、action

potential は再び現れる。神経細胞用には、hh2.mod などが作られている。実際の計算にはそれらを用いた方がよいと思われるが、mod ファイルをシステムに組込む作業が必要なので、当面は既に組込まれている

hh.mod を用いることとする。
(http://senselab.med.yale.edu/modeldb/ShowModel.asp?model=3817)

3.3 Connecting sections
次に、soma に apical dendrite を付け加える。create は同じ。connect でつなぐ。先にも述べたが、一般的に hoc の命令文（statement）は、いずれかの section に対して行なわれ、形式的には、section statementという形となる。複数の statement を {} で囲むことができる。ただし section と { の間に改行を入れないよ
うにする。section の情報は必ずしも明示的に示される訳ではない。access section により section の既定値を設定できる。

//-----------------------------------------------// n08.hoc:

soma + dendrite

create soma, ap_dendsoma {
L = 30diam = 30
nseg = 1
insert hh

9el_hh = -30}
ap_dend {L = 500
diam = 2
nseg = 23}
connect ap_dend(0), soma(1)tstop = 200
dt = 0.01
v_init = -65
objref fp
double a[4]fp = new File()
fp.wopen("a.dat")
finitialize(v_init)
fcurrent()
while(t<tstop){
fadvance()a[0] = ta[1] = soma.v(0.5)
a[2] = ap_dend.v(0.1)
a[3] = ap_dend.v(0.9)
fp.vwrite(4, &a)}
fp.close()
WinExec("gc a.dat")//------------------------------------------------. soma ap dend 2とのつの section より成り立っている。nseg で section 内の segment の数を示す。

この値は奇数でなくてはならない。soma および ap dend の近位部から測って 0.1 と 0.9 の部分の電位変化をプロットしている。活動電位が soma から ap dend に伝わっていることがわかる。

3.4 Point Process
3.4.1 AlphaSynapse
section とならんで重要な要素は、Point Process と呼ばれるものであり、シナプス入力（AlphaSynapse、
Exp2Syn）、current clamp（IClamp）、voltage clamp（VClapm）等がこれにあたる。これらの Point Process

10

20

0

-20

-40

-60

0

50

100

150

200

20

0

-20

-40

-60

80

85

90

95

Fig.2 n08.hoc: Potentials of soma (red), proximal dendrite(0.1) (blue), and distal dendrite(0.9)(green). The lower panel is a magnification.

はクラスとして定義されており、section に加える場合は、insert ではなく、次の方法で行なう。

objref pp
section pp = new PointProcess(x )x は、section での位置を示す。
dendrite にシナプス入力を入れる。soma の hh の leak 電流の平衡電位は、default の値に戻した。また
dendrite に soma の 1/10 の density で hh を加えた。
//-----------------------------------------------// n09.hoc
create soma, ap_dendsoma {
L = 30diam = 30
nseg = 1
insert hh}
ap_dend {L = 500
diam = 2
nseg = 2311insert hh
gnabar_hh = 0.012
gkbar_hh= 0.0036

gl_hh = 0.00003}
connect ap_dend(0), soma(1)// synaptic input
objref syn
ap_dend syn = new AlphaSynapse(0.5)
syn.onset = 5
syn.tau = 0.1
syn.gmax = 0.05
tstop = 20
dt = 0.01
v_init = -65
objref fp
double a[4]fp = new File()
fp.wopen("a.dat")
finitialize(v_init)
fcurrent()
while(t<tstop){
fadvance()a[0] = ta[1] = soma.v(0.5)
a[2] = ap_dend.v(0.1)
a[3] = ap_dend.v(0.9)
fp.vwrite(4, &a)}
fp.close()
WinExec("gc a.dat")//------------------------------------------------

12

20
0
-20
-40
-60

0

5

10

15

20

Fig.3 n09.hoc: Synaptically evoked action potential. Synaptic input at dendrite(0.5). Potentials
at soma (red), proximal dendrite(0.1) (blue), and distal dendrite(0.9) (green)

3.5 クラス
同じような神経細胞をいちいち定義するのは手間がかかる。クラス（テンプレート；鋳型）を定義し、クラスからオブジェクト（インスタンス）を作成すると、手間が省ける。
クラスの定義は、begintemplate class name と endtemplate class name で囲んだ部分。変数を明示的に初期化する関数 init() を用意することが必要である。public として宣言された変数、関数が外からアクセスすることが出来る。

3.6 NetCon、NetStim
神経細胞間の情報伝達は、神経軸索をつたわる活動電位を計算することによりシミュレーションすることが可能だが、いちいち計算しなくても伝達にかかる時間を delay として取り扱えば、計算量を大幅に減らすことができる。NetCon は delay を考慮に入れたシグナル伝達を扱う pipe メカニズムである。

objref nc
nc = new NetCon(src pp, target pp, threshould, delay, weight)
もしくは、

src section nc = new NetCon(&src range value, target pp, threshould, delay, weight)という形で定義される。ここで pp は point process を示す。src rannge value は、&v(0.5) の様に表す。

&soma.v(0.5) という表記はエラーとなる。
NetCon の情報は List() を用いて扱うと便利である。
objref nclist
nclist = new List()
nclist.append(new NetCon(src pp, target pp, threshould, delay, weight))
もしくは、

src section nclist.append(new NetCon(&src range value, target pp, threshould, delay, weight))
外部刺激に相当する Point Process メカニズムとして、NetStim クラスが用意されている。NetStim は、

NetCon の source としても target としても利用できる。パラメータとしては、interval、number、start、
noise などがある。
13

hh_neuron[0]stim

hh_neuron[1]

esyn

esyn

soma.vsoma.v

NetConFig.4 Two synaptically connected neurons.

//--------------------------------------// n10.hoc//--------------------------------------//

class definition
begintemplate HHneuron
public soma, ap_dend, esyn
create soma, ap_dend
objref esynproc init(){soma {
L = 30soma.diam = 30
soma.nseg = 1
soma insert hh}
ap_dend {L = 500
diam = 2
nseg = 23
insert hh
gnabar_hh = 0.012
gkbar_hh= 0.0036

gl_hh = 0.00003

14

}connect ap_dend(0), soma(1)ap_dend esyn = new Exp2Syn(0.5)
esyn.tau1 = 0.5
esyn.tau2 = 1.0
esyn.e = 0}
endtemplate HHneuron//--------------------------------------// cells
objref hh_neuron[2]hh_neuron[0] = new HHneuron()hh_neuron[1] = new HHneuron()// synapse
objref stim
stim = new NetStim(0.5)
stim.interval = 20
stim.number = 3
stim.start = 20
stim.noise = 0// connections
objref nclist
nclist = new List()
nclist.append( new NetCon(stim, hh_neuron[0].esyn, 0.0, 0, 0.02))
hh_neuron[0].soma nclist.append( new NetCon( &v(0.5), \hh_neuron[1].esyn, 10, 1, 0.02))//--------------------------------------tstop = 100
dt = 0.01
v_init = -65
objref fp
double a[3]fp = new File()
fp.wopen("a.dat")
finitialize(v_init)
fcurrent()
15

20
0
-20
-40
-60

0

20

40

60

80

100

Fig.5 n10.hoc: Synaptically connected neurons

while(t<tstop){
fadvance()a[0] = ta[1] = hh_neuron[0].soma.v(0.5)
a[2] = hh_neuron[1].soma.v(0.5)
fp.vwrite(3, &a)}
fp.close()
WinExec("gc a.dat")//---------------------------------------

NetCon で weight のパラメータを 0.02 から-0.02 に変えてみると、次の結果が得られた (図 3.6)。Reboundfiring を示している。ただしこの神経細胞は Na+ チャネル、K+ チャネル、leak チャネルを持っているだけで、low-threshold タイプの Ca2+ チャネルを有しているわけではない。

3.7 Voltage clamp
単一コンパートメント（soma のみ）にシナプス入力がある場合に、voltage clamp で測定する場合のシミュ
レーション。

//--------------------------------------//

n11.hoc//
create soma
objref esynobjref vcl

16

40
20
0
-20
-40
-60
-80
-100
0

20

40

60

Fig.6 Inhibitory connection

soma {
L = 30diam = 30
nseg = 1
esyn = new Exp2Syn(0.5)
insert hh
vcl = new VClamp(0.5)}// stimulation
objref stim
stim = new NetStim(0.5)
stim.interval = 50
stim.number = 2
stim.start = 50
stim.noise = 0// synaptic connections
objref nclist
nclist = new List()
nclist.append( new NetCon(stim, esyn, 0.0, 0, 0.005))//--------------------------------------tstop = 200
dt = 0.01
v_init = -65

17

80

100

vcl.dur[0] = 10
vcl.dur[1] = 10
vcl.dur[2] = 180
vcl.amp[0] = v_init
vcl.amp[1] = v_init
vcl.amp[2] = v_init
vcl.gain = 1000
vcl.tau1 = 0.01
vcl.tau2 = 0.01
objref fp
double a[3]fp = new File()
fp.wopen("a.dat")
finitialize(v_init)
fcurrent()
while(t<tstop){
fadvance()a[0] = ta[1] = soma.v(0.5)
a[2] = 1000 * vcl.i
fp.vwrite(3, &a)}
fp.close()system("gc a.dat")//--------------------------------------Voltage clamp で、シナプス電流の i-v relation を求める。基本的には上記のプログラムと同じ。holding
potential を変化させて繰り返しを行なっている。
//--------------------------------------//

n12.hoc// iv in voltage-clamp mode
tstop = 50
dt = 0.01
vstart = -100
vstep = 10// voltage step of holding potential

ntrace = 20// number of traces

npnt= tstop/dt

double a[npnt][ntrace+1]
18

200
100
0
-100
-200
-300
0

50

100

150

200

Fig.7 n11.hoc: Synaptic current measured in the voltage-clamp mode

objref vc, syn, ns, nc
create soma
soma {
diam = 30
L = 30nseg = 1
insert pas
vc = new VClamp(0.5)
vc.dur[0] = 10
vc.dur[1] = 10
vc.dur[2] = 30
syn = new Exp2Syn(0.5)
syn.e = 0}ns = new NetStim()
ns.number = 1
ns.start = 10
ns.noise = 0
nc = new List()
nc.append(new NetCon(ns,syn, 0, 0, 0.001))
for i=1, ntrace {v_init = vstart + vstep * (i-1)
vc.amp[0]=v_init
vc.amp[1]=v_init

19// 1 nS

50

0

-50

-100
0

10

20

30

40

50

Fig.8 n12.hoc: A group of synaptic current traces in the voltage-clamp mode

vc.amp[2]=v_init
e_pas = v_init
finitialize(v_init)
fcurrent()
for j = 0, npnt-1 {fadvance()if(i==1) a[j][0] = ta[j][i] = 100 * vc.i}}
objref fp
fp=new File()
fp.wopen("a.dat")
for j = 0, npnt-1 {fp.vwrite(ntrace+1, &a[j][0])}fp.close()system("gc a.dat")//---------------------------------------.

シナプス入力には Ex2Syn() を用いた。leak 電流には pas を用い、holding current を消すために、leak

電流の平衡電位が holding potential と同じであるとして計算している。2 次元の配列にデータを記録し、まとめてファイルに書き込んでいる。

soma より 10 本の dendrites がでており、soma で voltage clamp を行なった場合のシミュレーションは次のようになる。

20

//--------------------------------------//

n13.hoc//
create soma, dend[10]objref esynobjref vcl
soma {
L = 30Ra = 100
nseg = 1
diam = 30
insert hh
vcl = new VClamp(0.5)}
for i=0,9 {dend[i] {L = 300
Ra = 100
nseg = 21
diam=2
insert hh
gl_hh *= 2.3}}
dend[0] esyn = new Exp2Syn(0.75)
for i=0,9{
connect dend[i](0), soma(1)}// stimulation
objref stim
stim = new NetStim(0.5)
stim.interval = 50
stim.number = 2
stim.start = 50
stim.noise = 0// synaptic connections
objref nclist
21

nclist = new List()
nclist.append( new NetCon(stim, esyn, 0.0, 0, 0.001))//--------------------------------------tstop = 200
dt = 0.01
v_init = -65
vcl.dur[0] = 10
vcl.dur[1] = 10
vcl.dur[2] = 180
vcl.amp[0] = v_init
vcl.amp[1] = v_init
vcl.amp[2] = v_init
vcl.gain = 1000
vcl.tau1 = 0.1
vcl.tau2 = 0.1
objref fp
double a[4]fp = new File()
fp.wopen("a.dat")
finitialize(v_init)
fcurrent()
while(t<tstop){
fadvance()a[0] = ta[1] = soma.v(0.5)
a[2] = dend[0].v(0.75)
a[3] = 100 * vcl.i
fp.vwrite(4, &a)}
fp.close()
WinExec("gc a.dat")//---------------------------------------

22

-20
-30
-40
-50
-60
-70
0

50

100

150

200

Fig.9 n13.hoc: Synaptic current measured in the voltage-clamp mode (green). Synaptic input at
dendrite[0](0.75). The voltage-clamp electrode is positioned at soma. Potentials at soma (red) anddendrite[0](0.75) (blue). Currents are in nA, and magnified by a factor of 100.

23

4 Morphology
4.1 section
NEURON では、神経細胞の形態を円柱もしくは錐体の集まりとして表現している。それぞれのパーツは、
section と呼ばれる。表面として計算されるのは、円柱の側面に当たる部分であり、断面に当たる部分は考えに入れられていない。soma も、球体・楕円体ではなく円柱として考えられる。半径 r の球の表面積は、4πr 2で表されるが、長さ 2r、半径 r の円柱の側面の面積は、(2r) ∗ (2πr) なので、球の場合と同じになる。
長い円柱の場合、cable property を考慮に入れなくてはならない。NEURON では section を segment に分割して計算する機能を備えている。nseg は分割の値であり、演算の技術的な理由で、この値は奇数でなくてはならない。円柱の位置を示すには、分割された部分の番号ではなく、0 と 1 の間の値で示される Normalized

distance が用いられる。このために、nseg の値を変更しても、場所を示す値を変える必要はない。
nseg をどのような値にするかにより、計算の結果は異なってくる。通常は nseg = 3 程度でよいが、形態学的なデータに基づく枝分かれのあるモデルの場合は、nseg ≥ 9 が必要であるとされている。

section のパラメータとしては、次のものがある。
• L // Length [µm]• Ra // cytoplasmic registivity [Ωcm]• nseg // discretization parameter
それぞれの segment でのパラメータである Range variable には次のようなものがある。

• diam // diameter• cm // specific membrane capacitance [µf/cm2 ]• v // membrane potential [mV]• nai // internal sodium concentration [mM]range variable が、distance に対して linear に変化する場合、dend01.diam(0:1) = 1.5:1.0 というように書くことができる。このような値の設定は、各 segment 毎の値を入れているので、当然のことながら、nseg が先に与えられなくてはならない。

Dendrite に分岐がある場合にそれらを単一の dendrite として計算を行なう Rall の Cable 理論では、(dj )2/3 = (dk1 )2/3 + (dk2 )2/3 という条件を満たしている必要があった。

dk1
dj
dk2
Fig.10 Branching of dendrites

24nseg = 1
nseg = 2
nseg = 3
Fig.11 Calculation is performed at thenodes with red markings

しかし NEURON では、演算をおこなう点（node）を section のつながりの部分にも置いており、section間の条件は緩和されている。

4.2 geometory
神経細胞を模したモデルを作るには、soma、dendrite、axon などの section を create し、それらをつなげばよい。section をつなぐには、connect child( 0 or 1), parent ( x ) を用いる。これは、parent connect

child( 0 or 1), x と書いても同じである。
この操作を簡便にするために、Menu → Build → Cell Builder が用意されている。より複雑な形態をした神経細胞のデータ入力には、ファイルからの読み込で行なわれる。3 次元の座標（x, y, z）と半径 diam が与えられている場合、pt3dadd() を用いる。
入力したあるいは読み込んだデータの確認には、• section name psection() // parameters of a section• forall psection() // parameters for all sections• topology() // section connections• Menu → Graph → Shape plotが便利である。
実際に神経細胞の形態のデータを読み込むには、先ず dendrite を配列として create し、データを読み込
み、そして section を connect する。下記のような例を見ると参考になる。

• http://senselab.med.yale.edu/modeldb/ShowModel.asp?model=279 の tc200.geo、
これらの例では、ファイルからの読み込みの場合、hoc ファイルにプログラムコードとデータの数値が同一のファイルに入っているという、普通のプログラムから考えると奇妙な成り立ちになっている。これは、比較的初期の NEURON では、ファイルの入出力に制限（入力用にファイルが 1 つしか開けない）があったために、苦肉の策としてこのような形になったのではないかと思われる。しかしながら、これらのファイルは単に読み込むだけで形態のデータを取り込めるので非常に便利である。
通常これらのデータは、section の長さ（L）、直径（diam）および Connection を定義しているが、nseg
や Ra 等を含めて他の定義は行なっていないことに注意する必要がある。

load_file("tc200.geo")25なお、ソースコードとデータを分け、テキスト形式のデータファイルからデータを読み込むには、File クラスを用いて、次のようなコードを適宜書き換えて使用すればよい。古典的な ropen() と fscan() の組み合わ
せは、動かない。（クラス関数の.ropen() と ropen() は別物らしい。）//--------------------------------------objref fp
fp = new File()
fp.ropen("datafile.txt")// open for read

while(1){a = fp.scanvar()// fscan() does not work

printf ("a = %f\n", a)}fp.close()//---------------------------------------

4.3 segment の長さ
例を見ていると、100 µm を越えるような細長い section でも nseg=1 となっている。これでは具合が悪いであろうということは想像に難くない。シグナルの減弱は距離と周波数に関係しており、e-fold の減弱が生じ
る長さは、

√
λf ≈

d
πf Ra Cm12で表される。diam = 1 µm、Ra = 180 Ωcm、Cm = 1 µf/cm2 、Rm = 16,000 Ωcm2 とすると、λ100 ∼ 225µm となる。segment の長さ（L/nseg）の λf に対する比率パラメータを、d lambda と呼ぶ。d lambda の既定値は 0.1 である。（ただし、膜の時定数 τm が 8 ms 以下の場合はより小さい値を用いる必要がある。）目
安として、diam が 1 µm の場合、1 segment の長さは 20 µm 程度にするということになる。
自動的に nseg を決めるには、下のコードを用いる。これらの関数は stdlib.hoc に含まれている。

//--------------------------------------func lambda_f(){
return 1e5 * sqrt(diam/(4 * PI * $1 * Ra * cm))}proc geom_nseg(){soma area (0.5)
nseg = int ((L/(0.1*lambda_f(100)) + 0.9)/2) * 2 + 1}//--------------------------------------読み込んだ形態データを確認するために、いくつかの手段が用意されている。

• psection() コマンドで section の情報を示すことができる。ある特定の section の情報が知りたい場
26

合は、section psection()、全ての section の情報が知りたい場合は、forall psection() を用いる。

SectionList を利用する場合は、forsec section list psection()。
• topology() コマンドで、section がどのように connect されているかを示す。
• 図で示す。図で示す方法には用途に応じていくつかのやり方があるようであるが、一番基本的な方法
は、Shape クラスを用いる方法である。

objref sh
sh = new Shape(mode)
引数は mode で、0 の場合 diam、1 の場合 centroid、2 の場合直線で示される。mode は図の menu で変更可能。特定の section の色を変える方法は、section shape.color(color)。color は、2 が赤、3 が青である。 Point process をマークするには、shape.point mark(point process, color) が便利。
なお、Graph が表示されている状態で、NEURON Main Menu →Window →Print File Window Manager→Print →PostScript という操作により、図を PostScript（ps）ファイルに保存することができる。以後の処理は、外枠などの余分な図形があるので、ps ファイルを import して GUI で操作編集できるソフトが便利。

ps ファイルまたは eps（encapsulated postscript）ファイルを読み込むことができるソフトは比較的限られている。例えば、Adobe Illustrator（Windows, Mac OS）、Corel Draw（Windows）、Scribus*2（Linux, Mac

OS, Windows; Open Source）など。eps ファイフは bitmap データを含んでおり、PostScript の解釈をして図を描くのではなく、この bitmap 情報を使用するソフト（Microsoft Oﬃce など）では、編集はできない。

tc200 のモデルを読み込み、dendrite に random に 30 個のシナプスを作る例。
//------------------------------//

n14.hoc//load_file("nrngui.hoc")
load_file("stdlib.hoc")
load_file("tc200geo.hoc")//------------------------------nSyn=30
tstop = 200
dt = 0.01
v_init = -65//--------------------------------------objref dendritic, dendritic_only
objref sh
objref r, locvec, tx
objref esyn[nSyn]
objref sref
*2 http://www.scribus.net/

27

objref nclist
strdef s//------------------------------//

class definition//
begintemplate TimeClockpublic getSec
double jx[3]strdef datetime
func getSec(){// returns time in sec

system("date ’+%H %M %S’", datetime)sscanf(datetime,"%d%d%d", &jx[0], &jx[1], &jx[2])return (jx[0]*60 + jx[1])*60 + jx[2]}endtemplate TimeClock//------------------------------//

utilities//
func measureDist(){local dx localobj sr
dx = 0sr = new SectionRef()
while(sr.has_parent){
dx += L
access sr.parent
sr = new SectionRef()}
return dx}//------------------------------// Properties of dendrites//
dendritic = new SectionList()
forall {insert hh
Ra = 100
dendritic.append()}28

soma dendritic.remove()forsec dendritic {d = lambda_f(100)nseg = int((L/(0.1*d))+0.9)/2*2+1}// total dendritic length
total_length=0
forsec dendritic {total_length += L}
print "Tolal dendrite length = ", total_length//------------------------------// Shape Plotsh = new Shape(1)sh.size(-150, 150, -150, 150)//------------------------------// stimulation
objref stim
stim = new NetStim(0.5)
stim.interval = 50
stim.number = 2
stim.start = 50
stim.noise = 0
nclist = new List()//------------------------------// random generator
tx = new TimeClock()r = new Random(tx.getSec())
r.uniform(0, total_length)
locvec = new Vector(nSyn)
locvec.setrand(r)for k = 0, nSyn-1 {l=029

l1 = 0found = 0
forsec dendritic {if(found==0){
l1 += Lif(l1>locvec.x(k)){
lx = (locvec.x(k)-l)/L
sref = new SectionRef()
print secname(), measureDist()
sref.sec {esyn[k] = new Exp2Syn(lx)sh.color(2)}sh.point_mark(esyn[k],3)
nclist.append( new NetCon(stim, esyn[k], 0.0, 0, 0.001))
found = 1
break}l = l1}}}
sh.flush()
doEvents()//------------------------------// main loop
objref fp
fp = new File()
fp.wopen("a.dat")
double a[2]finitialize(v_init)
fcurrent()
while(t<tstop){
fadvance()a[0] = ta[1] = soma.v(0.5)
30

Fig.12 n14.hoc: tc neuron and random synapses

fp.vwrite(2, &a)}
fp.close()system("~/bin/gc a.dat")//------------------------------------------------

Windows/Cygwin の場合、system(cmd) は動くが、system(cmd, string) にバグがあるようだ。そのバグを回避するために、次のコードを使用する。

begintemplate TimeClockpublic getSec
double jx[3]strdef datetime31

func getSec(){// returns time in sec

system("date ’+%H %M %S’> tmp001.txt")// changed

ropen("tmp001.txt")// added

getstr(datetime)// addedropen()// addedsystem("rm tmp001.txt")// addedsscanf(datetime,"%d%d%d", &jx[0], &jx[1], &jx[2])return (jx[0]*60 + jx[1])*60 + jx[2]}endtemplate TimeClock
次に、n 次以上の dendrite 分岐に一様に synapse 入力がある場合を考える。mesureDis()、countBranch()を呼ぶことにより access している section が変化しないように改良。シナプスの数は 100 個。synaptic

delay は正規分布の乱数を用い、平均 10 ms、標準偏差 1 ms としている。synaptic delay は負の数になるとエラーを起こすことに注意。

//------------------------------//

n15.hoc//load_file("nrngui.hoc")
load_file("tc200geo.hoc")//------------------------------tstop = 200
dt = 0.01
v_init = -65
nSyn=100// number of synapses

mdel = 10// mean of synaptic delaysdel = 1// sd of synaptic delay

w = 0.001// synaptic weight

br = 5//--------------------------------------objref dendritic, dendriticN
objref sh
objref r, vloc, vdel, tx
objref esyn[nSyn]
objref sref
objref nc
32

strdef s//------------------------------//

class definition//
begintemplate TimeClockpublic getSec
double jx[3]strdef datetime
func getSec(){// returns time in sec

system("date ’+%H %M %S’", datetime)sscanf(datetime,"%d%d%d", &jx[0], &jx[1], &jx[2])return (jx[0]*60 + jx[1])*60 + jx[2]}endtemplate TimeClock//------------------------------//

utilities//
func measureDist(){local dx localobj sr, srsave
dx = 0srsave = new SectionRef()
sr = new SectionRef()
while(sr.has_parent){
dx += L
access sr.parent
sr = new SectionRef()}
access srsave.sec
return dx}
func countBranch(){local bx localobj sr, srsave
bx = 0srsave = new SectionRef()
sr = new SectionRef()
while(sr.has_parent){
if(sr.nchild==2){
bx += 133

}access sr.parent
sr = new SectionRef()}
access srsave.sec
return bx}//------------------------------// Properties of dendrites//
dendritic = new SectionList()
forall {insert hh
Ra = 100
dendritic.append()}
soma dendritic.remove()forsec dendritic {d = lambda_f(100)nseg = int((L/(0.1*d))+0.9)/2*2+1}
dendriticN = new SectionList()
total_length=0
forall {if(countBranch()>=br){dendriticN.append()
total_length += L}}
print "total length of \">=", br, "-branch\" dendrites = ", total_length//------------------------------// Shape Plotsh = new Shape(1)//------------------------------34

// stimulation
objref stim
stim = new NetStim(0.5)
stim.interval = 50
stim.number = 2
stim.start = 50
stim.noise = 0//------------------------------// random generator
tx = new TimeClock()r = new Random(tx.getSec())
r.uniform(0, total_length)// synaptic location

vloc = new Vector(nSyn)
vloc.setrand(r)r.normal(mdel,sdel*sdel)// synaptic delay

vdel = new Vector(nSyn)
vdel.setrand(r)nc = new List()
for k = 0, nSyn-1 {l=0
l1 = 0found = 0
forsec dendriticN {if(found==0){
l1 += Lif(l1>vloc.x(k)){
lx = (vloc.x(k)-l)/L
sref = new SectionRef()
print secname(), ", dist=", measureDist(), \", br=", countBranch(), ", delay=", vdel.x(k)sref.sec {esyn[k] = new Exp2Syn(lx)sh.color(2)}sh.point_mark(esyn[k],3)35

nc.append(new NetCon(stim, esyn[k], 0.0, vdel.x(k), w))
found = 1
break}l = l1}}}
sh.flush()
doEvents()//------------------------------// main loop
objref fp
double a[2]fp = new File()
fp.wopen("a.dat")
print "Sim Start"
finitialize(v_init)
fcurrent()
while(t<tstop){
fadvance()a[0] = ta[1] = soma.v(0.5)
fp.vwrite(2, &a)}
fp.close()system("~/bin/gc a.dat &")// -- end of file36

Fig.13 n15.hoc; 100 random synapses

20
0
-20
-40
-60

0

50

100

150

200

Fig.14 赤：n14.hoc のトレース、青：n15.hoc のトレース

37

5 Spikes
5.1 NetCon
神経細胞集団の活動場合、膜電位 v の変化よりも活動電位あるいはスパイクのタイミング、数の方が解析の対象となってくる。スパイクの記録は NetCon の.record() を用いて行なうことができる。神経細胞が List ク
ラスのオブジェクト cells であり、それぞれの神経細胞にあるポイントプロセス pp がスパイクを表すとする。

//------------------------------objref spikes
objref netcon, vec
spikes = new List()
for i=0, cells.count()-1 {vec = new Vector()
netcon = new NetCon(cells.object(i).pp, nill)
netcon.record(vec)spikes.append(vec)}objref netcon, vec//------------------------------vec には、event が起きた実時間が記録される。スパイクのデータをファイルに記録するには、Vector クラスの関数.vwrite(fp) が便利である。［データ数: 4-byte integer］［4: 4-byte integer］［データ 0: 8-byte

double］［データ 1: 8-byte double］.....［データ N: 8-byte double］という binary の形式でファイルに書かれる。2 番目の値 4 は、データが double であることを示す。

//------------------------------objref fp
fp.wopen("a.nrb")
for i=0, spikes.count()-1 {vec.vwrite(fp)}fp.close()//-------------------------------

5.2 Raster Plot の描き方
ここではラスタープロットを描く関数を示す。local な変数はできるだけ local に宣言し、他の関数との混乱を防ぐようにしている。使い方は、あらかじめ Graph オブジェクトを用意しておき、データファイル（たとえば a.nrb）を読みこむ。

objref gr
38

gr = new Graph()
plotRaster(gr, ”a.nrb”)//------------------------------//

plotRaster(Graph, String)proc plotRaster(){ local nn, ts \localobj fp, spikes, vec, spikey
fp = new File()
fp.ropen($s2)
if(!fp.isopen()){ return }nn = 0ts = 0spikes = new List()
while(!fp.eof()){
vec = new Vector()
vec.vread(fp)spikes.append(vec)nn += 1xx = vec.x(vec.size()-1)
if(ts < xx){ ts = xx }}fp.close()$o1.view(0, 0, ts, nn, 100, 100, 400, 200)
$o1.erase_all()for i=0, nn-1{
spikey = spikes.object(i).cspikey.fill(i+1)
spikey.mark($o1, spikes.object(i), "|", 6)}}//------------------------------この関数について特にコメントをすることはないが、NEURON における Vector の扱い方の参考になる。

39

6 NMODLNMODL は NEURON 版の MODL（MOdel Description Language）である。MODL は NEURON だけでなく Genesis などの他のシステムでも用いられており、NMODL で書かれたファイル（mod ファイル）は、原
則的には他のシステムでも利用可能である。mod ファイルの内部は、PARAMETER、STATE、ASSIGNED
等のいくつかのブロックに分かれている。ブロックの種類の中で NEURON ブロックは、NEURON に特有のものである。

mod ファイルは、nocmodl により C 言語のファイルに変換されて、その後 gcc（C コンパイラ）によりコンパイルされる。Windows の場合、nrnmech.dll が作成されて実行時に oc に組み込まれる。従って新たな mod
ファイルを使用する場合にも、oc インタープリタ本体のコンパイルをする必要はない。MacOS と Linux の場合、special という名前の実行形式のスクリプトが生成される。このスクリプトは新たに作成されたダイナ
ミックライブラリ（{umac, i686}/.libs/libnrnmech.so）を読み込む。
実際の操作は、Windows の場合、mknrndll のアイコンをクリックし、mod ファイルがあるディレクト
リを選択する。コマンドラインから操作を行う場合、mod ファイルが置かれているディレクトリに移動
して、$NEURONHOME/bin にある mknrndll という shell script を使えばよい。ただしこの scirpt では

NEURONHOME を示す変数 N が定義されていないので、
N=/cygdrive/c/nrn62
export Nの 2 行を付け加えなくてはならない。

Mac の場合は、mod ファイルのあるディレクトリ（フォルダ）のアイコンを mknrndll のアイコンに重ねる。コマンドラインからの場合は、mod ファイルが置かれているディレクトリに移動し、open -a mknrndll.

とする（”.”は言うまでもなく current directory の意味）。そのディレクトリ内に umac（Mac Universal

BInary の意で、ppc と intel 系の両方の CPU で稼働できる）という名前のディレクトリが作成され、その中に special という実行可能なファイルが作られる。

Mac の場合でも、ソースコードからコンパイルした場合には、アイコンや application bundle が作成されない場合がある。そのような場合は、nrniv などが含まれる bin ディレクトリにある nrnivmodl という名前のシェルスクリプトを使用して、nrnivmodl . とする。”.”はあってもなくても構わないようだ。

6.1 Blocks
mod ファイルでコメントは、COMMENT と ENDCOMMENT で挟まれた行、あるいは”:”で始まる行である。また VERBATIM と ENDVERBATIM に挟まれた行は、nocmodl で処理されることなくそのまま C
言語ファイルになる。

6.1.1 NEURON block
SUFFIX でモジュールの名前を定義する。RANGE で外からアクセスできる変数を示す。

40

6.1.2 ASSIGNED block
mod ファイル外で値をいれる変数、あるいは mod ファイル内で式の左側に来る変数。
6.1.3 STATE block
微分法的式などで用いられる変数。変数は ASSIGNED と STATE の両方で宣言することは出来ない。

6.1.4 INITIAL block
初期化ブロック。関数 finitialize(v init) から各 module の INITITAL block が使われる。

6.1.5 BREAKPOINT block
実際の計算の場所。微分方程式を解く場合は SOLVE を用いる。方法としては、cnexp（Crank-Nicolson
法）、runge（Runge-Kutta 法）、euler（Euler 法）、derivimplicit などが使用可能。これらの方法は、いずれも一定の dt を用いる fixed step method である。通常は cnexp。runge は求められる以上の精度のため使用されない（時間がかかる）。
状況によって積分の細かさを変化させる adaptive integrator の方法としては、CVODE 法が利用可能である。

6.1.6 DERIVATIVE block
ここには常微分方程式がくる。

6.1.7 NET RECEIVE block
NetCon のために拡張された部分らしい。event が起きた時に何をするかを記述する部分。

6.2 例：常微分方程式を解いてみる
試しに簡単な常微分方程式の数値解を求めるのに NEURON を使用してみる。まず簡単な常微分方程式で試してみる。

z ′′ = −z
初期値は、z(0) = 0, z ′ (0) = 1 とする。z1 = z ′ と置くと、

z ′ = z1z1′ = −z連立の微分方程式として表すことが出来る。

:--------------------------------------: m01.mod:a simple ODE

z(t)’’ = -z(t)NEURON{SUFFIX m01
RANGE z41

}STATE {z z1}
INITIAL{z = 0
z1 = 1}
BREAKPOINT{SOLVE zstates METHOD cnexp}
DERIVATIVE zstates {z’ = z1
z1’ = -z}:--------------------------------------この mod ファイルを試すための hoc ファイル。

//--------------------------------------// m01.hoc:

test file for mo1.mod

create soma
soma insert m01
tstop = 100
dt = 0.01
v_init = -65
objref fp
fp = new File()
fp.wopen("a.dat")
double a[2]finitialize(v_init)
fcurrent()
while(t<tstop){
fadvance()a[0] = tsoma a[1] = z_m01
fp.vwrite(2,&a)
}
42

1.0

0.5

0.0

-0.5

-1.0
0

20

40

60

80

100

Fig.15 m01.hoc: m10.mod 内で cnexp を用いて数値計算。

1.5
1.0
0.5
0.0
-0.5
-1.0
-1.5
0

20

40

60

80

100

Fig.16 m01.hoc: m10.mod 内で異なる数値計算法を用いた。cnexp（赤; 緑に重なっている）、euler（青）、runge（緑）。

fp.close()
WinExec("gc a.dat")//---------------------------------------

6.3 IntervalFire
NEURON Book に掲載されている Interval File を掲載する。人工細胞であり、変数 m は、微分方程式dm= (m∞ − m)/τdt

43

に従い、その値が 1 を越えると fire して m = 0 に戻る。 外からに入力があると、m の値が w だけ変化する。
この式は解析的に解けて、m(t = 0) = 0 とすれば、tm = m∞ (1 − exp(− ))τで示される。t = invl の時、m = 1 であるから、m∞ =1
1 − exp(− invl
τ )

である。

: ------------------------------------------------------------------------:The NEURON Book pp. 309- 310

NEURON {ARTIFICIAL_CELL IntervalFire: name of the module

RANGE tau, m, invl

: accessible variables}
PARAMETER {tau = 5 (ms)

<1e-9,1e9>

invl = 10 (ms) <1e-9,1e9>}
ASSIGNED {: non-accessible variablesm
minf
t0 (ms)}INITIAL {minf = 1/(1 - exp(-invl/tau)) : so natural spike interval is invl
m = 0
t0 = 0
net_send(firetime(), 1): set a self-event: after time period of firetime()}
NET_RECEIVE (w) {m = M()
t0 = tif (flag == 0) {: *** event triggered by others ***m = m + w
if (m > 1) {m = 0
net_event(t): issue event}44net_move(t+firetime())}else{: move the next event to t + firetime(): *** self-triggered event ***net_event(t): issue eventm = 0
net_send(firetime(), 1): next self-event}}
FUNCTION firetime()(ms) {: m < 1 and minf > 1

firetime = tau*log((minf-m)/(minf - 1))}
FUNCTION M() {: to monitor m-value

M = minf + (m - minf)*exp(-(t - t0)/tau)}: -------------------------------------------------------------------------. NetConに関しては十分な Reference がないので、この例は NetCon をどのように使用すればよいかを理解するために、とても参考となる例である。ここで使用されている NetCon に関係する関数は下記の通り。

• net event(t1 ) 時間 t1 に event を発生させる。event は NetCon で定義された相手全てに伝えられる。
• net send(t2 , f lag) 現時点 t より t2 後に event を発生させる。f lag = 0 の場合は他に、f lag = 1 の場合は self へ event が送られる。

• net move(t3 ) 詳細は不明。次に起きる予定の self event を t3 へと移動させるらしい。
INITIAL block では、m∞ の値を求めるとともに、m の値を初期化している。t0 は event が発生からの時間を示す。さらに INITIAL block で net send() を用いて次の event が起きるように設定している。firetime()
は次の event が起きるまでの時間を計算する関数。ここでは invl でもよい。

event が起きた場合、NET RECEIVE block が実行される。引数 w は NetCon の weight であり、正負の値を取ることができる。何を実行するはか、m の値に依存するが、m の値は常々計算されている訳ではない
ので、まずは明示的に m の値を（場合によっては計算して）入れる。event が起きた時刻として t0 をアップデートする。

f lag は event が自己由来か他由来かを示すフラグで、0 の場合は他、1 の場合は自己であることを示す。他か
らの event を受け取った場合、新しい m の値は m+w となる。もしそれが 1 を越えていたなら、net event()
で event を発生させる。m の値が変化したので、次の event 予定をキャンセルして、net move() を用いて

firetime()+t にセットし直す。
自己から発せられた event の場合は、event を発生させ、次の自己宛の event を net send() でセットする。

m の値は NET RECEIVE block でしか計算されない。m の挙動をしらべるため、関数 M を定義している。M の値はアクセスされるたびに更新されている。関数 X の返す値は、X() ではなく X で示すことができる。

45

6.4 Synaptic transmission
先ず標準の Point process である exp2syn の内容を検討する。event が起きたた場合に、2 つの指数関数の和で表されるコンダクタンスの変化を示す。

: ------------------------------------------------------------------------:

nrn-6.1src/nrnoc/exp2syn.mod

NEURON {POINT_PROCESS Exp2Syn
RANGE tau1, tau2, e, i
NONSPECIFIC_CURRENT i
RANGE gGLOBAL total}
UNITS {(nA) = (nanoamp)(mV) = (millivolt)(uS) = (microsiemens)}
PARAMETER {tau1= 0.1 (ms) <1e-9,1e9>
tau2 = 10 (ms) <1e-9,1e9>e=0 (mV)}ASSIGNED {v (mV)i (nA)g (uS)
factortotal (uS)}
STATE {A (uS)
B (uS)}INITIAL {LOCAL tp46

total = 0
if (tau1/tau2 > .9999) {: avoid tau1==tau2

tau1 = .9999*tau2
}
A = 0
B = 0
tp = (tau1*tau2)/(tau2 - tau1) * log(tau2/tau1)
factor = -exp(-tp/tau1) + exp(-tp/tau2)
factor = 1/factor}
BREAKPOINT {SOLVE state METHOD cnexp
g = B - Ai = g*(v - e)}
DERIVATIVE state {A’ = -A/tau1
B’ = -B/tau2}
NET_RECEIVE(weight (uS)) {A = A + weight*factor
B = B + weight*factor
total = total+weight}: -------------------------------------------------------------------------. t=0の時に入力があったとすると、コンダクタンス g の時間的な変化は、()
ttg = f actor exp(−) − exp(−
)
tau2
tau1

で表される。f actor は、g の最大値が 1 となるようにするための係数である。f actor の値を求めるために、gが極値をとる t の値 tp を求める。

(
)
dg
1
t
1
t
= f actor −
exp(−
)+
exp(−
)
dt
tau2
tau2
tau1
tau1

47

t = tp の時 dg/dt = 0 であるから、
1
tp
1
tp
exp(−
)=
exp(−
)
tau2
tau2
tau1
tau1
tp
tp
tau1 exp(−) = tau2 exp(−
)
tau2
tau1
tp
tp
log(tau1) −= log(tau2) −
tau2
tau1
(
)
1
1
tau2
−
)
tp = log(
tau1 tau2
tau1
tau1 ∗ tau2
tau2
tp =
log(
)
tau2 − tau1
tau1
従って、

. NET RECEIVE block

(
)
tp
tp
f actor = 1/ exp(−) − exp(−
)
tau2
tau1
で行なっていることは、状態の設定し直し（一種の初期化とも言える）であり、各 time step での計算は、BREAKPOINT block（実態は DERIVATIVE block）で行なわれている。



元のソースコードでは、A = A + weight*factor の部分が、state discontinuity(A, A+weight*factor)と書かれている。この state discontinuity() という関数は、微分方程式で変数が abrupt に変化した場合のトラブルを回避するためのものであるが、NET RECEIVE block の改良により用いる必要はなくなっている。

par

6.5 Synaptic plasticity
これも NEURON Book からの転載であるが、Use-dependent synaptic plasticity の例を示す。このコードは、nrn-6.1/share/examples/niniv/netcon/gsyn.mod と同じもの。上記の例から推測されるように、

NET RECEIVE block で、event が起きればその時刻を記録しておき、次の event が起きた時に前の event
からの時間によってシナプス結合の強度を調節するようにすればよい。変数の記憶には、NetCon の機能が用いられる。

: ------------------------------------------------------------------------:The NEURON Book pp. 281-282: ------------------------------------------------------------------------:The NEURON Book pp. 281-282

NEURON {POINT_PROCESS GSynRANGE tau1, tau2, e, i
RANGE Gtau1, Gtau2, Ginc
NONSPECIFIC_CURRENT i
RANGE g}
UNITS {
48

(nA)

=

(nanoamp)(mV)=(millivolt)(umho)=(micromho)}
PARAMETER {
tau1

= 1

(ms)

tau2

= 1.05 (ms)

Gtau1

= 20

(ms)

Gtau2

= 21

(ms)

Ginc

= 1

e

= 0

(mV)

}
ASSIGNED {
v

(mv)

i

(nA)

g

(umho)

factor
Gfactor}
STATE {A (umho)B (umho)}
INITIAL {LOCAL tp
A = 0
B = 0
tp = (tau1*tau2)/(tau2-tau1) * log(tau2/tau1)
factor = -exp(-tp/tau1) + exp(-tp/tau2)
factor = 1/factor
tp = (Gtau1*Gtau2)/(Gtau2-Gtau1) * log(Gtau2/Gtau1)
Gfactor = -exp(-tp/Gtau1) + exp(-tp/Gtau2)
Gfactor = 1/Gfactor}
BREAKPOINT {SOLVE state METHOD cnexp
g = B - Ai = g * (v - e)}
DERIVATIVE state {49

A’ = -A/tau1
B’ = -B/tau2}
NET_RECEIVE (weight (umho), w, G1, G2, t0 (ms)){
G1 = G1*exp(-(t-t0)/Gtau1)
G2 = G2*exp(-(t-t0)/Gtau2)
G1 = G1 + Ginc * Gfactor
G2 = G2 + Ginc * Gfactor
t0 = tw = weight * (1 + G2 - G1)
A = A + w*factor
B = B + w*factor}: -------------------------------------------------------------------------. NET RECEIVE blockの引数。引数の数が 1 の場合、NetCon の weight が渡される。引数が n + 1

個の場合、最初の引数は、NetCon の weight であり、残りの引数はこの mod の変数を NetCon で記憶しておくために用いられる。これらの引数は、通常の”call by value”ではなく、”call by reference”で渡されるので、NET RECEIVE block で変更された値は NetCon で保存される。

6.6 NMDA receptor channel
NMDA receptor channel は Mg2+ block により電位依存性と活動依存性を示す。下記の mod ファイルは、
Gasparini et al, J Neurosci 24:11046-11056, 2004 による。state discontinuity() を取除く等の改変を行なっている。

http://senselab.med.yale.edu/modeldb/ShowModel.asp?model=44050: ------------------------------------------------------------------------NEURON {POINT_PROCESS nmdanet
RANGE R, g, mg
NONSPECIFIC_CURRENT i
GLOBAL Cdur, Alpha, Beta, Erev, Rinf, Rtau}
UNITS {(nA) = (nanoamp)(mV) = (millivolt)(umho) = (micromho)(mM) = (milli/liter)}
PARAMETER {

50

Cdur

= 1

(ms)

: transmitter duration (rising phase)Alpha= 0.35 (/ms)

Beta= 0.035 (/ms) : backward (unbinding) rateErev

= 0 (mV): reversal potentialmg= 1 (mM): external magnesium concentration

v

(mV)

: postsynaptic voltage

i

(nA)

: current = g*(v - Erev)g(umho): conductance: forward (binding) rate}
ASSIGNED {

Rinf
Rtau

: steady state channels open(ms)

: time constant of channel binding

synon}
STATE {Ron Roff}
INITIAL {Rinf = Alpha / (Alpha + Beta)
Rtau = 1 / (Alpha + Beta)synon = 0}
BREAKPOINT {SOLVE release METHOD cnexp
g = mgblock(v)*(Ron + Roff)*1(umho)
i = g*(v - Erev)}
DERIVATIVE release {Ron’ = (synon*Rinf - Ron)/Rtau
Roff’ = -Beta*Roff}
FUNCTION mgblock(v(mV)) {TABLE
DEPEND mg
FROM -140 TO 80 WITH 1000
mgblock = 1 / (1 + exp(0.062 (/mV) * -v) * (mg / 3.57 (mM)))}
NET_RECEIVE(weight, on, nspike, r0, t0 (ms)) {if (flag == 0) { : a spike, so turn on if not already in a Cdur pulse
nspike = nspike + 151

if (!on) {r0 = r0*exp(-Beta*(t - t0))
t0 = ton = 1synon = synon + weightRon =Ron + r0

Roff = Roff - r0}
net_send(Cdur, nspike)}if (flag == nspike) { : if this associated with last spike then turn off
r0 = weight*Rinf + (r0 - weight*Rinf)*exp(-(t - t0)/Rtau)
t0 = tsynon = synon - weight
Ron = Ron - r0
Roff = Roff + r0
on = 0}}: ------------------------------------------------------------------------n12.hoc を NMDA receptor channel に変更して Voltage-clamp mode で I-V relationship を得ると、Ma2+
block の効果がわかる。
25

25
20

20

15

15

10

10

5

5

0
0

-5
0

10

20

30

40

50

52

-50

0

50

100

7 NEURON の内部
7.1 初期化
finitialize()

7.2 Integration の方法
7.3 Graph

53

付録 A

インストールの仕方

現在 (2012 年 7 月) の最新バージョンは 7.2。
インストールの方法は、http://www.neuron.yale.edu/neuron/install/install.html に記載されている。当然のことながら OS によって異なる。Unix/Linux で開発されてきたプログラムなので、OS によってうまく働かない機能があるようだ。

A.1 Windows の場合
Windows 用とは言うものの、Unix/Linux に似た環境を提供する Cygwin のサブセットを用いている。
nrn-n.n.setup.exe をダウンロードする。そのプログラムを起動しインストールを行う（この作業は管理者権限が必要）。インストールされた先を環境変数 PATH に加える。（コントロールパネル → システム → 詳細設定

→ 環境変数で、ユーザー環境変数に、例えば、PATH=%PATH%;C:Y=nrn72 bin と設定する。%PATH% はシステムとして設定された PATH）。
注意すべき点として、cygwin では PATH の中に空白文字があるとトラブルの原因となるので、インストー
ル先は、C:Y=Program Files の中に nrn70 を置くのではなく、C:Y=nrn70 とか C:Y=WIN32APPY=nrn70 といった所にするのがよい。

cygwin のサブセットがインストールされるので、C 言語のプログラムをコンパイルし走らせる事が出来る。
gcc.exe は含まれているが、g++.exe は含まれていないので、C++ 言語のプログラムの処理は出来ない。
また、cygwin のシステムや MinGW のシステムがインストールされていると、パスの検索で混乱を生じる事がある。

A.2 Mac OS の場合
Mac OS の場合は、dmg ファイルをダウンロードして解凍し、NEURON-n.n のフォルダを Applications
フォルダにコピーするだけで完了。

PATH を/Applications/NEURON-n.n/nrn/umac/bin に通しておくと便利である。あるいは、$HOMEに bin ディレクトリをつくって PATH を通しておき、そこに nrniv 等の symbolic link を置く方法もある。

ln -s /Applications/NEURON-n.n /nrn/i686/bin/nrniv nrniv
ln -s /Applications/NEURON-n.n /nrn/i686/bin/nrngui nrngui
つ い で な が ら 、MacOS に お け る PATH の 設 定 の 仕 方 を 書 い て お く 。そ の な か で 、1,2,4 はDYLD LIBRARY PATH の 設 定 に も 使 え る 。い う ま で も な い が 、1,2 は ユ ー ザ ー を 対 象 と し 、3,4 はコンピュータ全体を対象としている。

1. ∼/.bash profile を使用。最も古典的な方法。コマンドラインからプログラムを起動する時は問題ない
が、アイコンをクリックして起動する場合に PATH を読み込まない、という問題が生ずる。

2. ∼/.MacOSX/environment.plist で設定。コマンドライン、アイコンの両方で OK。
3. /etc/paths
先に現れる方が優先度が高くなります。/etc/paths.d を使う事も可能。

54

4. /etc/launchd.conf で設定。
Mac OS の場合、開発環境がインストールしてあれば、ソースコードから簡単にコンパイルすることが出来る。Snow Leopard もしくはそれ以前の OS では、開発環境は OS の DVD に含まれているが、デフォールトではインストールされていない。Lion では、ダウンロードする必要がある。NEURON のコンパイルの方法
は、上記のウェブサイトに書かれており、その通りすれば出来るはずである。Intel CPU のマシンであれば、–

enable-carbon のオプションは使用しない。トラブルがなければ 20 分程度で完了できる。–enable-carbon のオプションをつけると umac ディレクトリが作成され、–enable-carbon のオプションをつけないと i686 ディ
レクトリが作成されるようである。

A.3 Linux の場合
インストールの方法は、Mac OS とほぼ同じ。

A.4 計算速度
計算速度に関しては正確に測定したことはないが、CPU のスペックが同じ程度であれば MacOS よりも

Windows の方が速いようである。MacOS の場合は、異なる CPU に使用できるようにしているために遅くなっているのかと想像される。実際、ソースコードを–enable-carbon のオプションなしでコンパイルすると、Intel CPU 専用のプログラムが作成され、実行速度は 1.5〜2 倍となった（MacBook Pro の場合）。また Core
2 Duo や Xeon などでは 64-bit で計算を行うようにコンパイルするのがよい（どのように設定する？）。
NEURON のコンパイルには、Windows/MacOS/Linux のいずれでも GNU C/C++ コンパイラを使用している。 Intel コンパイラを使用すれば速度面での改善が予測される。iv（InterViews）なしではコンパイル可能であるとの報告あり*3 。

付録 B

hoc ファイル用のテキストエディタ

hoc ファイルの作成・編集にはテキストエディタを用いる。notepad（Windows）や TextEdit（Mac OS）などのテキストエディタでよいが、行番号がわかりやすい方がよく、また定義が色でハイライト（syntax

highlight）されるとさらに便利である。

B.1 Emacs 系テキストエディタ
Windows 用、Mac 用、Linux 用すべてあり
プログラマ好みのエディタである emacs は、様々な機能を有しており、また機能拡張も可能である。高機能
すぎて取っ付きにくい。hoc ファイルの syntax highlight を設定をするには、nrnhoc.el がある*4 。行番号の表示には linum.el を使用。

*3 http://www.neuron.yale.edu/phpBB/viewtopic.php?=6&t=116*4 http://homepages.inf.ed.ac.uk/sterratt/progs/neuron

55

B.2 Notepad++Windows 用プログラム
行番号の表示あり。syntax highlight の機能はあるが、hoc ファイルでは働かない (設定ファイルが用意されていないのだろう)。

B.3 Coteditor
MacOS 用プログラム
行番号の表示あり。syntax highlight の機能はあるが、hoc ファイルでは働かない (設定ファイルが用意されていないのだろう)。

付録 C

References• The NEURON Book. Carnevale NT & Hines ML, Cambridge University Press, 2006.
NEURON の開発者による説明書であり、NEURON の説明書としてはもっともまとまった本。ただしこの本だけでは情報が十分でないところもある。

• Programmer’s Reference。命令、関数等の詳細を調べるために便利。少ないながら example もある。
zip ファイルをダウンロードして使用することも可能。
http://www.neuron.yale.edu/neuron/docs/help/contents.html• The NEURON Forum。NEURON に関する質問サイト。多くの質問に Carnevale 自身が回答している。プログラムのちょっとした工夫等が書かれている。

http://www.neuron.yale.edu/phpBB/• ModelDB。データ、プログラムのデータベース。大部分が NEURON 用のもの。
http://senselab.med.yale.edu/modeldb/• Hines ML & Carnevale NT (2004) Discrete event simulation in the NEURON environment. Neurocomputing Volumes 58-60, Pages1117-1122.

56