COMMENT

This is a mechanism for computing sliding BCM threshold based on recent spike count (Benuskova et al. PNAS 2001, Benuskova and Abraham JCNS 2007):

alpha_scount = alpha * scount 

The averaged postsynaptic activity scount expresses the weighted
average of the postsynaptic spike count, with the most recent
spikes entering the sum with bigger weight than previous
ones. 

output = 1, if there is a postsynaptic spike
at a given time, output = 0, otherwise.

alpha is the scaling constant.

scounttau is the averaging time constant for calculation of alpha_scount.

The mechanism should be inserted into soma to calculate the value of alpha_scount and thereby of d and p for all synaptic point processes which use d, p as POINTER variables.
At the hoc level d and p have to be set up as POINTER variables to allow the synaptic point process to know the d and p value. Here is an example
for setting up POINTER variables for a synaptic object syn: 

setpointer syn.d, d_BCMthreshold
setpointer syn.p, p_BCMthreshold

ENDCOMMENT

NEURON {
	POINT_PROCESS BCMthreshold
	GLOBAL d0, p0, scount0, scounttau, alpha, alpha_scount
	GLOBAL d, p, tspike
}

UNITS {
	(mV) = (millivolt)
}

PARAMETER {
	
	d0		: initial value for the depression factor (additive, non-saturating)
	p0		: initial value for the potentiation factor (additive, non-saturating)

	scounttau  		: averaging time constant for postsynaptic spike count, e.g. 12000 ms
	alpha			: scaling constant
	
	scount0 		: initial scount = 0 
	boltzman = 0	: initial boltzman = 0 (from Luba)

}

ASSIGNED {
	v (mV)
	flagOLD
	
	alpha_scount	: scount scaled by alpha - sliding (scount-dependent) modification threshold
	d			: depression factor (multiplicative to prevent < 0)
	p			: potentiation factor (multiplicative)
	boltzfactor 	: from Luba
	pf				: from Luba
	output			: from Luba
	tspike (ms)
}
STATE {
	scount			: counter for postsynaptic spikes
}
INITIAL {
	
	tspike = -100000
	
:flag is an implicit argument to NET_RECEIVE. It is an integer, zero by default but a nonzero value can be specified via the second argument to
:net_send(). net_send() is used to launch self-events. A self-event comes back to the mechanism that launched it, no NetCon required. 

	net_send(0, 1)
	flagOLD = 1
	scount = scount0
	d = d0		
	p = p0
	alpha_scount = alpha*scount
	boltzfactor = exp( - 1.0 / scounttau)
	if(boltzman == 0) {pf = 1.0 / (1 - boltzfactor)} else {pf = 1.0}
	output = 0
}

BREAKPOINT { 
	:if (output > 0) {printf("entry time=%g output=%g\n", t, output)}
	scount = scount  + output/pf
	SOLVE state METHOD cnexp								:credit to Steffen Platschek
  	pf = pf * boltzfactor + 1.0
  	alpha_scount = alpha * scount							:scount scaled by alpha
	if (alpha_scount > 0) {p = p0/alpha_scount} else {p = p}
	d = d0*alpha_scount
    output = 0
}

DERIVATIVE state{
	scount' = -scount / pf
}

:The items in the argument list in the NET_RECEIVE statement of a synaptic mechanism are actually the elements of a
:weight vector. The first element, which is called nc.weight[0],
:corresponds to the first item in the NET_RECEIVE argument list--w--which remains constant during a simulation.
:The second element is called nc.weight[1], and it corresponds to wE.
:The value of this second element DOES change as a consequence of STDP.

NET_RECEIVE(w) {		:w is actually not needed for computations
	INITIAL {w=0}

:When a presynaptic spike occurs, the mechanism receives an event with flag == 0. 
:The printf statements are purely for diagnostic purposes and can be commented out.

	if (flag == 0) {
		output = 0 			:no postsynaptic spike
	} else if (flag == 2) { 	: postsynaptic spike
		tspike = t				: just in case one needs time of the spike
		output = 1				:postsynaptic spike 
		:printf("output=%g at time t=tspike=%g\n", scount, tspike)
	} else { : flag == 1 from INITIAL block

		:printf("entry flag=%g t=%g\n", flag, t)

:WATCH (var > thresh) flagvalue is used in a NET_RECEIVE block to specify a condition in the postsynaptic cell
:that will generate a self-event with latency 0 and a specified flag value. Generally, WATCH is used to make NEURON
:monitor a variable for threshold crossing, and generates a self event with the specified flag value when the threshold
:is crossed. If the postsynaptic cell is a biophysical model cell, var is usually local membrane potential (or cai or some
:other concentration); if the postsynaptic cell is an artificial spiking cell, var is one of that cell's state variables.
:But WATCH could in principle be anything, such as the total number of spikes that a cell has fired, or perhaps even t (time)

		WATCH (v > 0) 2 :This mechanism watches postsynaptic membrane potential at the location of the mechanism
						:When a postsynaptic spike occurs, the mechanism receives an event with flag == 2
	}
}