// Synaptic Plasticity for GABAergic Synapses
//
// Copyright 2007 John L Baker. All rights reserved.
//
// This software is provided AS IS under the terms of the Open Source
// MIT License. See http://www.opensource.org/licenses/mit-license.php.
//
// File: plasticity_gaba_baker_2003.cpp
//
// Release: 1.0.0
// Author: John Baker
// Updated: 14 July 2006
//
// Description:
//
// This file contains the classes used to implement
// GABA synapse plasticity. Two version were considered: one from
// data involving regular spike trains (Scanziani) and the
// other from single pulse pairings (Otis et al.). Of these,
// the spike train data is probably more representative.
//
// References: see header file
#include "plasticity_gaba_baker_2003.h"
using namespace std;
using namespace BNSF;
using namespace UOM;
using namespace BAKER_2003;
// ================================================================
// GABA Presynaptic Rule Class for paired pulse depression
// ================================================================
// Static values
const TokenId GABA_PresynapticRule::_GABA_PresynapticId
= token("GABA_PresynapticRule");
// Set event quantity based on the presynaptic rule (Scanziani, 2000)
void GABA_PresynapticRule::finalizeAPEvent(ActionPotentialEvent* apEvent)
{
// Handle initial spike explicitly since exp
// does unhelpful things with infinite values.
// Since this is a one-time event, we assume
// release occurs unconditionally just this once.
if (apEvent->isi()==InfiniteFuture) {
apEvent->quantity(1);
}
// Otherwise, compute the ongoing PPF or PPD value
else {
Number isi = apEvent->isi();
Number ppfd;
// Get the paired pulse adjustment and set the event quantity
ppfd = 1+a0()*qdexp(-isi/tau());
ppfd *= 1+AChA()*AChLevel()/( AChLevel() + AChKd() );
// Set quantity to either 0 or 1 if random release or pp if not.
if (useRandomRelease() ) {
apEvent->quantity( synapticCond()->runif()<ppfd ? 1 : 0 );
}
else {
apEvent->quantity(ppfd);
}
}
// Indicate that this event has been handled
apEvent->isFinal(true);
}
// Apply an ACh neuromodulation rule
void GABA_PresynapticRule::setModParams(TokenId id, int nv, Number* values)
{
using namespace UOM;
static const TokenId AChMod = token("AChModulator");
// Skip any other forms of modulation and check num of params
if (id!=AChMod) return;
if (nv<1) {
FatalError("(GABA_PresynapticRule::setModParams) "
"Too few parameter values supplied");
}
// Set the new concentration value
AChLevel( values[0] );
}
// ================================================================
// GABAb Postsynaptic Rule Class
// ================================================================
// Constructors and destructor
GABAb_PostsynapticRule::GABAb_PostsynapticRule(
Number baseWght,
Number amparInc,
SimTime tau)
{
// Save parameters
_baseWeight = baseWght;
_amparIncrement = amparInc;
_tauW = tau;
// Initialize other values
_amparInitialized = false;
_weight = _baseWeight;
}
GABAb_PostsynapticRule::~GABAb_PostsynapticRule() {}
// Locate associated AMPAR
void GABAb_PostsynapticRule::locateAMPAR()
{
static const int numIds = 2;
static const TokenId respToFind[numIds] = {
token("AC_GluR"),
token("PP_GluR")
};
int k;
Compartment* comp = synapticCond()->container();
// Discard any AMPAR previously located
if (_amparInitialized) {
_ampar.resize(0);
}
// Try to find each synaptic response type and save the address.
// There is no danger of any of these going away unexpectedly.
for (k=0; k<numIds; k++) {
SynapticResponse* resp;
// Locate the associated response and if found, remember it
resp = comp->findSynapticResponse(respToFind[k],false);
if (resp!=NULL) {
_ampar.push_back(resp);
}
}
}
// Take action at the end of the time step (before AP purge)
// This should be done after the glutamate plasticity updates are done,
// but weights change slowly enough it really does not matter.
void GABAb_PostsynapticRule::applyEndOfStep(ActionPotentialEventQueue& apQueue)
{
SynapticResponseVectorIt it;
SimTime h = timeStepSize();
SimTime tau = tauW();
Number totalAMPARWeight=0;
Number targetWeight;
int synapseCount=0;
// Make sure AMPAR have been located in this compartment.
// This is postponed until first use to simplify start-up.
if (!_amparInitialized) {
locateAMPAR();
_amparInitialized=true;
}
// Get an average synaptic weight by going through each
// associated AMPAR response type and accumulating.
for (it=_ampar.begin(); it!=_ampar.end(); it++) {
SynapticResponse* resp = *it;
int n;
totalAMPARWeight += resp->totalSynapticWeight(&n);
synapseCount += n;
}
// Now get the resulting GABAb synapse weight. This value
// is accessed by the associated response and used to adjust
// conductance.
targetWeight = baseWeight();
if (synapseCount>0) {
targetWeight += totalAMPARWeight/synapseCount * amparIncrement();
}
// Move current weight towards target weight using a time
// constant of tau. A rough approximation is used assuming
// that tauW is much larger than the current time step.
// Otherwise, qdexp might be appropriate here.
_weight += h/(tau+h/2)*(targetWeight - _weight);
}