diff --git a/biophysics/CaConc.cpp b/biophysics/CaConc.cpp index 91dd8fce01..5e717184c7 100644 --- a/biophysics/CaConc.cpp +++ b/biophysics/CaConc.cpp @@ -14,43 +14,43 @@ const Cinfo* CaConc::initCinfo() { - static string doc[] = - { - "Name", "CaConc \n", - "Author", "Upinder S. Bhalla, 2014, NCBS \n", - "Description", "CaConc: Calcium concentration pool. Takes current from a \n" - "channel and keeps track of calcium buildup and depletion by a \n" - "single exponential process. \n", - }; - - static Dinfo< CaConc > dinfo; - - static Cinfo CaConcCinfo( - "CaConc", - CaConcBase::initCinfo(), - 0, - 0, - &dinfo, - doc, - sizeof(doc)/sizeof(string) - ); - - return &CaConcCinfo; + static string doc[] = + { + "Name", "CaConc \n", + "Author", "Upinder S. Bhalla, 2014, NCBS \n", + "Description", "CaConc: Calcium concentration pool. Takes current from a \n" + "channel and keeps track of calcium buildup and depletion by a \n" + "single exponential process. \n", + }; + + static Dinfo< CaConc > dinfo; + + static Cinfo CaConcCinfo( + "CaConc", + CaConcBase::initCinfo(), + 0, + 0, + &dinfo, + doc, + sizeof(doc)/sizeof(string) + ); + + return &CaConcCinfo; } /////////////////////////////////////////////////// static const Cinfo* caConcCinfo = CaConc::initCinfo(); CaConc::CaConc() - : CaConcBase(), - Ca_( 0.0 ), - CaBasal_( 0.0 ), - tau_( 1.0 ), - B_( 1.0 ), - c_( 0.0 ), - activation_( 0.0 ), - ceiling_( 1.0e9 ), - floor_( 0.0 ) + : CaConcBase(), + Ca_( 0.0 ), + CaBasal_( 0.0 ), + tau_( 1.0 ), + B_( 1.0 ), + c_( 0.0 ), + activation_( 0.0 ), + ceiling_( 1.0e9 ), + floor_( 0.0 ) {;} /////////////////////////////////////////////////// @@ -59,38 +59,38 @@ CaConc::CaConc() void CaConc::vSetCa( const Eref& e, double Ca ) { - Ca_ = Ca; + Ca_ = Ca; } double CaConc::vGetCa( const Eref& e ) const { - return Ca_; + return Ca_; } void CaConc::vSetCaBasal( const Eref& e, double CaBasal ) { - CaBasal_ = CaBasal; + CaBasal_ = CaBasal; } double CaConc::vGetCaBasal( const Eref& e ) const { - return CaBasal_; + return CaBasal_; } void CaConc::vSetTau( const Eref& e, double tau ) { - tau_ = tau; + tau_ = tau; } double CaConc::vGetTau( const Eref& e ) const { - return tau_; + return tau_; } void CaConc::vSetB( const Eref& e, double B ) { - B_ = B; + B_ = B; } double CaConc::vGetB( const Eref& e ) const { - return B_; + return B_; } void CaConc::vSetCeiling( const Eref& e, double ceiling ) { @@ -98,7 +98,7 @@ void CaConc::vSetCeiling( const Eref& e, double ceiling ) } double CaConc::vGetCeiling( const Eref& e ) const { - return ceiling_; + return ceiling_; } void CaConc::vSetFloor( const Eref& e, double floor ) @@ -107,7 +107,7 @@ void CaConc::vSetFloor( const Eref& e, double floor ) } double CaConc::vGetFloor( const Eref& e ) const { - return floor_; + return floor_; } /////////////////////////////////////////////////// @@ -116,45 +116,48 @@ double CaConc::vGetFloor( const Eref& e ) const void CaConc::vReinit( const Eref& e, ProcPtr p ) { - activation_ = 0.0; - c_ = 0.0; - Ca_ = CaBasal_; - concOut()->send( e, Ca_ ); + activation_ = 0.0; + c_ = 0.0; + Ca_ = CaBasal_; + concOut()->send( e, Ca_ ); } void CaConc::vProcess( const Eref& e, ProcPtr p ) { - double x = exp( -p->dt / tau_ ); - Ca_ = CaBasal_ + c_ * x + ( B_ * activation_ * tau_ ) * (1.0 - x); - if ( ceiling_ > 0.0 && Ca_ > ceiling_ ) { - Ca_ = ceiling_; - } else if ( Ca_ < floor_ ){ - Ca_ = floor_; - } - c_ = Ca_ - CaBasal_; - concOut()->send( e, Ca_ ); - activation_ = 0; + double x = exp( -p->dt / tau_ ); + Ca_ = CaBasal_ + c_ * x + ( B_ * activation_ * tau_ ) * (1.0 - x); + if ( ceiling_ > 0.0 && Ca_ > ceiling_ ) + { + Ca_ = ceiling_; + } + else if ( Ca_ < floor_ ) + { + Ca_ = floor_; + } + c_ = Ca_ - CaBasal_; + concOut()->send( e, Ca_ ); + activation_ = 0; } void CaConc::vCurrent( const Eref& e, double I ) { - activation_ += I; + activation_ += I; } void CaConc::vCurrentFraction( const Eref& e, double I, double fraction ) { - activation_ += I * fraction; + activation_ += I * fraction; } void CaConc::vIncrease( const Eref& e, double I ) { - activation_ += fabs( I ); + activation_ += fabs( I ); } void CaConc::vDecrease( const Eref& e, double I ) { - activation_ -= fabs( I ); + activation_ -= fabs( I ); } /////////////////////////////////////////////////// @@ -165,52 +168,52 @@ void CaConc::vDecrease( const Eref& e, double I ) void testCaConc() { /* - CaConc cc; - double tau = 0.10; - double basal = 0.0001; - - cc.setCa( basal ); - cc.setCaBasal( basal ); - cc.setTau( tau ); - // Here we use a volume of 1e-15 m^3, i.e., a 10 micron cube. - cc.setB( 5.2e-6 / 1e-15 ); - // Faraday constant = 96485.3415 s A / mol - // Use a 1 pA input current. This should give (0.5e-12/F) moles/sec - // influx, because Ca has valence of 2. - // So we get 5.2e-18 moles/sec coming in. - // Our volume is 1e-15 m^3 - // So our buildup should be at 5.2e-3 moles/m^3/sec = 5.2 uM/sec - double curr = 1e-12; - // This will settle when efflux = influx - // dC/dt = B*Ik - C/tau = 0. - // so Ca = CaBasal + tau * B * Ik = - // 0.0001 + 0.1 * 5.2e-6 * 1e3 = 0.000626 - - ProcInfo p; - p.dt = 0.001; - p.currTime = 0.0; + CaConc cc; + double tau = 0.10; + double basal = 0.0001; + + cc.setCa( basal ); + cc.setCaBasal( basal ); + cc.setTau( tau ); + // Here we use a volume of 1e-15 m^3, i.e., a 10 micron cube. + cc.setB( 5.2e-6 / 1e-15 ); + // Faraday constant = 96485.3415 s A / mol + // Use a 1 pA input current. This should give (0.5e-12/F) moles/sec + // influx, because Ca has valence of 2. + // So we get 5.2e-18 moles/sec coming in. + // Our volume is 1e-15 m^3 + // So our buildup should be at 5.2e-3 moles/m^3/sec = 5.2 uM/sec + double curr = 1e-12; + // This will settle when efflux = influx + // dC/dt = B*Ik - C/tau = 0. + // so Ca = CaBasal + tau * B * Ik = + // 0.0001 + 0.1 * 5.2e-6 * 1e3 = 0.000626 + + ProcInfo p; + p.dt = 0.001; + p.currTime = 0.0; Eref sheller(Id().eref()); Shell * shell = reinterpret_cast (sheller.data()); Id temp = shell->doCreate("CaConc", Id(), "caconc", 1); assert(temp.element()->getName() == "caconc"); - // Id tempId = Id::nextId(); - // Element temp( tempId, CaConc::initCinfo(), "temp", 0 ); - Eref er( &temp, 0 ); - cc.reinit( er, &p ); - - double y; - double conc; - double delta = 0.0; - for ( p.currTime = 0.0; p.currTime < 0.5; p.currTime += p.dt ) - { - cc.current( curr ); - cc.process( er, &p ); - y = basal + 526.0e-6 * ( 1.0 - exp( -p.currTime / tau ) ); - conc = cc.getCa(); - delta += ( y - conc ) * ( y - conc ); - } - assert( delta < 1e-6 ); - cout << "." << flush; + // Id tempId = Id::nextId(); + // Element temp( tempId, CaConc::initCinfo(), "temp", 0 ); + Eref er( &temp, 0 ); + cc.reinit( er, &p ); + + double y; + double conc; + double delta = 0.0; + for ( p.currTime = 0.0; p.currTime < 0.5; p.currTime += p.dt ) + { + cc.current( curr ); + cc.process( er, &p ); + y = basal + 526.0e-6 * ( 1.0 - exp( -p.currTime / tau ) ); + conc = cc.getCa(); + delta += ( y - conc ) * ( y - conc ); + } + assert( delta < 1e-6 ); + cout << "." << flush; */ } #endif diff --git a/biophysics/CaConc.h b/biophysics/CaConc.h index 5aadb1d62c..66318d64ee 100644 --- a/biophysics/CaConc.h +++ b/biophysics/CaConc.h @@ -16,8 +16,8 @@ * without diffusion. It uses a simple exponential return of Ca * to baseline, with influxes from ion channels. It solves the * equation: - * dC/dt = B*Ik - C/tau - * where Ca = Ca_base + C. + * + * dC/dt = B*Ik - C/tau, where Ca = Ca_base + C. * * From the GENESIS notes: * In SI units, where concentration is moles/m^3 @@ -35,44 +35,44 @@ class CaConc: public CaConcBase { - public: - CaConc(); - /////////////////////////////////////////////////////////////// - // Message handling functions - /////////////////////////////////////////////////////////////// - void vReinit( const Eref&, ProcPtr info ); - void vProcess( const Eref&, ProcPtr info ); +public: + CaConc(); + /////////////////////////////////////////////////////////////// + // Message handling functions + /////////////////////////////////////////////////////////////// + void vReinit( const Eref&, ProcPtr info ); + void vProcess( const Eref&, ProcPtr info ); - void vCurrent( const Eref& e, double I ); - void vCurrentFraction( const Eref& e, double I, double fraction ); - void vIncrease( const Eref& e, double I ); - void vDecrease( const Eref& e, double I ); - /////////////////////////////////////////////////////////////// - // Field handling functions - /////////////////////////////////////////////////////////////// - void vSetCa( const Eref& e, double val ); - double vGetCa( const Eref& e ) const; - void vSetCaBasal( const Eref& e, double val ); - double vGetCaBasal( const Eref& e ) const; - void vSetTau( const Eref& e, double val ); - double vGetTau( const Eref& e ) const; - void vSetB( const Eref& e, double val ); - double vGetB( const Eref& e ) const; - void vSetCeiling( const Eref& e, double val ); - double vGetCeiling( const Eref& e ) const; - void vSetFloor( const Eref& e, double val ); - double vGetFloor( const Eref& e ) const; + void vCurrent( const Eref& e, double I ); + void vCurrentFraction( const Eref& e, double I, double fraction ); + void vIncrease( const Eref& e, double I ); + void vDecrease( const Eref& e, double I ); + /////////////////////////////////////////////////////////////// + // Field handling functions + /////////////////////////////////////////////////////////////// + void vSetCa( const Eref& e, double val ); + double vGetCa( const Eref& e ) const; + void vSetCaBasal( const Eref& e, double val ); + double vGetCaBasal( const Eref& e ) const; + void vSetTau( const Eref& e, double val ); + double vGetTau( const Eref& e ) const; + void vSetB( const Eref& e, double val ); + double vGetB( const Eref& e ) const; + void vSetCeiling( const Eref& e, double val ); + double vGetCeiling( const Eref& e ) const; + void vSetFloor( const Eref& e, double val ); + double vGetFloor( const Eref& e ) const; - static const Cinfo* initCinfo(); - private: - double Ca_; - double CaBasal_; - double tau_; - double B_; - double c_; - double activation_; - double ceiling_; - double floor_; + static const Cinfo* initCinfo(); +private: + double Ca_; + double CaBasal_; + double tau_; + double B_; + double c_; + double activation_; + double ceiling_; + double floor_; }; diff --git a/biophysics/CaConcBase.cpp b/biophysics/CaConcBase.cpp index fb6d07ec9e..e1b650c499 100644 --- a/biophysics/CaConcBase.cpp +++ b/biophysics/CaConcBase.cpp @@ -33,114 +33,114 @@ SrcFinfo1< double >* CaConcBase::concOut() const Cinfo* CaConcBase::initCinfo() { - /////////////////////////////////////////////////////// // Shared message definitions - /////////////////////////////////////////////////////// - static DestFinfo process( "process", - "Handles process call", - new ProcOpFunc< CaConcBase >( &CaConcBase::process ) ); - static DestFinfo reinit( "reinit", - "Handles reinit call", - new ProcOpFunc< CaConcBase >( &CaConcBase::reinit ) ); + static DestFinfo process("process", + "Handles process call", + new ProcOpFunc< CaConcBase >( &CaConcBase::process ) + ); + + static DestFinfo reinit("reinit", + "Handles reinit call", + new ProcOpFunc< CaConcBase >( &CaConcBase::reinit ) + ); static Finfo* processShared[] = { &process, &reinit }; - static SharedFinfo proc( "proc", - "Shared message to receive Process message from scheduler", - processShared, sizeof( processShared ) / sizeof( Finfo* ) ); + static SharedFinfo proc("proc", + "Shared message to receive Process message from scheduler", + processShared, sizeof( processShared ) / sizeof( Finfo* ) + ); - /////////////////////////////////////////////////////// // Field definitions - /////////////////////////////////////////////////////// static ElementValueFinfo< CaConcBase, double > Ca( "Ca", "Calcium concentration.", &CaConcBase::setCa, - &CaConcBase::getCa - ); - static ElementValueFinfo< CaConcBase, double > CaBasal( "CaBasal", + &CaConcBase::getCa); + + static ElementValueFinfo< CaConcBase, double > CaBasal("CaBasal", "Basal Calcium concentration.", &CaConcBase::setCaBasal, - &CaConcBase::getCaBasal - ); - static ElementValueFinfo< CaConcBase, double > Ca_base( "Ca_base", + &CaConcBase::getCaBasal); + + static ElementValueFinfo< CaConcBase, double > Ca_base("Ca_base", "Basal Calcium concentration, synonym for CaBasal", &CaConcBase::setCaBasal, - &CaConcBase::getCaBasal - ); - static ElementValueFinfo< CaConcBase, double > tau( "tau", + &CaConcBase::getCaBasal); + + static ElementValueFinfo< CaConcBase, double > tau("tau", "Settling time for Ca concentration", &CaConcBase::setTau, - &CaConcBase::getTau - ); - static ElementValueFinfo< CaConcBase, double > B( "B", + &CaConcBase::getTau); + + static ElementValueFinfo< CaConcBase, double > B("B", "Volume scaling factor. " "Deprecated. This is a legacy field from GENESIS and exposes " "internal calculations. Please do not use. \n" "B = 1/(vol * F* VALENCE) so that it obeys:\n" "dC/dt = B*I_Ca - C/tau", &CaConcBase::setB, - &CaConcBase::getB - ); + &CaConcBase::getB); + static ElementValueFinfo< CaConcBase, double > thick( "thick", "Thickness of Ca shell, assumed cylindrical. Legal range is between 0 \n" "and the radius. If outside this range it is taken as the radius. \n" " Default zero, ie, the shell is the entire thickness of the cylinder \n", &CaConcBase::setThickness, - &CaConcBase::getThickness - ); + &CaConcBase::getThickness); + static ElementValueFinfo< CaConcBase, double > length( "length", "Length of Ca shell, assumed cylindrical", &CaConcBase::setLength, - &CaConcBase::getLength - ); + &CaConcBase::getLength); + static ElementValueFinfo< CaConcBase, double > diameter( "diameter", "Diameter of Ca shell, assumed cylindrical", &CaConcBase::setDiameter, - &CaConcBase::getDiameter - ); + &CaConcBase::getDiameter); + static ElementValueFinfo< CaConcBase, double > ceiling( "ceiling", "Ceiling value for Ca concentration. If Ca > ceiling, Ca = ceiling. \n" "If ceiling <= 0.0, there is no upper limit on Ca concentration value.", &CaConcBase::setCeiling, - &CaConcBase::getCeiling - ); + &CaConcBase::getCeiling); + static ElementValueFinfo< CaConcBase, double > floor( "floor", "Floor value for Ca concentration. If Ca < floor, Ca = floor", &CaConcBase::setFloor, - &CaConcBase::getFloor - ); + &CaConcBase::getFloor); + /////////////////////////////////////////////////////// // MsgDest definitions /////////////////////////////////////////////////////// static DestFinfo current( "current", - "Calcium Ion current, due to be converted to conc.", - new EpFunc1< CaConcBase, double >( &CaConcBase::current ) - ); + "Calcium Ion current, due to be converted to conc.", + new EpFunc1< CaConcBase, double >( &CaConcBase::current ) + ); static DestFinfo currentFraction( "currentFraction", - "Fraction of total Ion current, that is carried by Ca2+.", - new EpFunc2< CaConcBase, double, double >( &CaConcBase::currentFraction ) - ); + "Fraction of total Ion current, that is carried by Ca2+.", + new EpFunc2< CaConcBase, double, double >( &CaConcBase::currentFraction ) + ); static DestFinfo increase( "increase", - "Any input current that increases the concentration.", - new EpFunc1< CaConcBase, double >( &CaConcBase::increase ) - ); + "Any input current that increases the concentration.", + new EpFunc1< CaConcBase, double >( &CaConcBase::increase ) + ); static DestFinfo decrease( "decrease", - "Any input current that decreases the concentration.", - new EpFunc1< CaConcBase, double >( &CaConcBase::decrease ) - ); + "Any input current that decreases the concentration.", + new EpFunc1< CaConcBase, double >( &CaConcBase::decrease ) + ); static DestFinfo basal( "basal", - "Synonym for assignment of basal conc.", - new EpFunc1< CaConcBase, double >( &CaConcBase::setCaBasal ) - ); + "Synonym for assignment of basal conc.", + new EpFunc1< CaConcBase, double >( &CaConcBase::setCaBasal ) + ); static Finfo* CaConcBaseFinfos[] = { diff --git a/biophysics/CaConcBase.h b/biophysics/CaConcBase.h index c215e84e52..b7f017d6a3 100644 --- a/biophysics/CaConcBase.h +++ b/biophysics/CaConcBase.h @@ -37,91 +37,91 @@ class CaConcBase { - public: - CaConcBase(); - /////////////////////////////////////////////////////////////// - // Message handling functions - /////////////////////////////////////////////////////////////// - void reinit( const Eref&, ProcPtr info ); - void process( const Eref&, ProcPtr info ); +public: + CaConcBase(); + /////////////////////////////////////////////////////////////// + // Message handling functions + /////////////////////////////////////////////////////////////// + void reinit( const Eref&, ProcPtr info ); + void process( const Eref&, ProcPtr info ); - void current( const Eref& e, double I ); - void currentFraction( const Eref& e, double I, double fraction ); - void increase( const Eref& e, double I ); - void decrease( const Eref& e, double I ); - /////////////////////////////////////////////////////////////// - // Virtual Message handling functions - /////////////////////////////////////////////////////////////// - virtual void vReinit( const Eref&, ProcPtr info ) = 0; - virtual void vProcess( const Eref&, ProcPtr info ) = 0; + void current( const Eref& e, double I ); + void currentFraction( const Eref& e, double I, double fraction ); + void increase( const Eref& e, double I ); + void decrease( const Eref& e, double I ); + /////////////////////////////////////////////////////////////// + // Virtual Message handling functions + /////////////////////////////////////////////////////////////// + virtual void vReinit( const Eref&, ProcPtr info ) = 0; + virtual void vProcess( const Eref&, ProcPtr info ) = 0; - virtual void vCurrent( const Eref& e, double I ) = 0; - virtual void vCurrentFraction( const Eref& e, double I, double fraction ) = 0; - virtual void vIncrease( const Eref& e, double I ) = 0; - virtual void vDecrease( const Eref& e, double I ) = 0; - /////////////////////////////////////////////////////////////// - // Field handling functions - /////////////////////////////////////////////////////////////// - void setCa( const Eref& e, double val ); - double getCa( const Eref& e ) const; - void setCaBasal( const Eref& e, double val ); - double getCaBasal( const Eref& e ) const; - void setTau( const Eref& e, double val ); - double getTau( const Eref& e ) const; - void setB( const Eref& e, double val ); - double getB( const Eref& e ) const; - void setCeiling( const Eref& e, double val ); - double getCeiling( const Eref& e ) const; - void setFloor( const Eref& e, double val ); - double getFloor( const Eref& e ) const; - void setThickness( const Eref& e, double val ); - double getThickness( const Eref& e ) const; - void setLength( const Eref& e, double val ); - double getLength( const Eref& e ) const; - void setDiameter( const Eref& e, double val ); - double getDiameter( const Eref& e ) const; - /////////////////////////////////////////////////////////////// - // Virtual Field handling functions - /////////////////////////////////////////////////////////////// - virtual void vSetCa( const Eref& e, double val ) = 0; - virtual double vGetCa( const Eref& e ) const = 0; - virtual void vSetCaBasal( const Eref& e, double val ) = 0; - virtual double vGetCaBasal( const Eref& e ) const = 0; - virtual void vSetTau( const Eref& e, double val ) = 0; - virtual double vGetTau( const Eref& e ) const = 0; - virtual void vSetB( const Eref& e, double val ) = 0; - virtual double vGetB( const Eref& e ) const = 0; - virtual void vSetCeiling( const Eref& e, double val ) = 0; - virtual double vGetCeiling( const Eref& e ) const = 0; - virtual void vSetFloor( const Eref& e, double val ) = 0; - virtual double vGetFloor( const Eref& e ) const = 0; + virtual void vCurrent( const Eref& e, double I ) = 0; + virtual void vCurrentFraction( const Eref& e, double I, double fraction ) = 0; + virtual void vIncrease( const Eref& e, double I ) = 0; + virtual void vDecrease( const Eref& e, double I ) = 0; + /////////////////////////////////////////////////////////////// + // Field handling functions + /////////////////////////////////////////////////////////////// + void setCa( const Eref& e, double val ); + double getCa( const Eref& e ) const; + void setCaBasal( const Eref& e, double val ); + double getCaBasal( const Eref& e ) const; + void setTau( const Eref& e, double val ); + double getTau( const Eref& e ) const; + void setB( const Eref& e, double val ); + double getB( const Eref& e ) const; + void setCeiling( const Eref& e, double val ); + double getCeiling( const Eref& e ) const; + void setFloor( const Eref& e, double val ); + double getFloor( const Eref& e ) const; + void setThickness( const Eref& e, double val ); + double getThickness( const Eref& e ) const; + void setLength( const Eref& e, double val ); + double getLength( const Eref& e ) const; + void setDiameter( const Eref& e, double val ); + double getDiameter( const Eref& e ) const; + /////////////////////////////////////////////////////////////// + // Virtual Field handling functions + /////////////////////////////////////////////////////////////// + virtual void vSetCa( const Eref& e, double val ) = 0; + virtual double vGetCa( const Eref& e ) const = 0; + virtual void vSetCaBasal( const Eref& e, double val ) = 0; + virtual double vGetCaBasal( const Eref& e ) const = 0; + virtual void vSetTau( const Eref& e, double val ) = 0; + virtual double vGetTau( const Eref& e ) const = 0; + virtual void vSetB( const Eref& e, double val ) = 0; + virtual double vGetB( const Eref& e ) const = 0; + virtual void vSetCeiling( const Eref& e, double val ) = 0; + virtual double vGetCeiling( const Eref& e ) const = 0; + virtual void vSetFloor( const Eref& e, double val ) = 0; + virtual double vGetFloor( const Eref& e ) const = 0; - /////////////////////////////////////////////////////////////// - // Utility function in case length, dia or thickness is updated - void updateDimensions( const Eref& e ); + /////////////////////////////////////////////////////////////// + // Utility function in case length, dia or thickness is updated + void updateDimensions( const Eref& e ); - /// Used to set up the solver. Dummy for regular classes. - virtual void vSetSolver( const Eref& e, Id hsolve ); + /// Used to set up the solver. Dummy for regular classes. + virtual void vSetSolver( const Eref& e, Id hsolve ); - /** - * Swaps Cinfos in order to make Zombies. - */ - static void zombify( Element* orig, const Cinfo* zClass, - Id hsolve ); + /** + * Swaps Cinfos in order to make Zombies. + */ + static void zombify( Element* orig, const Cinfo* zClass, + Id hsolve ); - /* - * This Finfo is used to send out Ca concentration to channels. - * - * It is exposed here so that HSolve can also use it to send out - * Ca concentration to the recipients. - */ - static SrcFinfo1< double >* concOut(); + /* + * This Finfo is used to send out Ca concentration to channels. + * + * It is exposed here so that HSolve can also use it to send out + * Ca concentration to the recipients. + */ + static SrcFinfo1< double >* concOut(); - static const Cinfo* initCinfo(); - private: - double thickness_; - double diameter_; - double length_; + static const Cinfo* initCinfo(); +private: + double thickness_; + double diameter_; + double length_; }; diff --git a/python/moose/__init__.py b/python/moose/__init__.py index 8749afda5f..ae08cb5cc0 100644 --- a/python/moose/__init__.py +++ b/python/moose/__init__.py @@ -1,6 +1,9 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function +import logging +logging.basicConfig(format='%(asctime)-15s %(name)-12s %(levelname)-8s %(message)s') + # Bring everything from c++ module to global namespace. from moose._moose import * diff --git a/python/moose/model_utils.py b/python/moose/model_utils.py index d4b7e21f23..ba62c29347 100644 --- a/python/moose/model_utils.py +++ b/python/moose/model_utils.py @@ -26,13 +26,12 @@ import moose.neuroml2 as _neuroml2 except Exception as e: nml2Import_ = False - nml2ImportError_ = ' '.join( [ - "NML2 support is disabled because `libneuroml` and " - , "`pyneuroml` modules are not found.\n" - , " $ pip install pyneuroml libneuroml \n" - , " should fix it." - , " Actual error: %s " % e ] - ) + nml2ImportError_ = ' '.join([ + "NML2 support is disabled because `libneuroml` and ", + "`pyneuroml` modules are not found.\n", + " $ pip install pyneuroml libneuroml \n", " should fix it.", + " Actual error: %s " % e + ]) chemImport_, chemError_ = True, '' try: @@ -55,6 +54,7 @@ mergechemImport_ = False mergechemError_ = '%s' % e + # SBML related functions. def mooseReadSBML(filepath, loadpath, solver='ee', validate="on"): """Load SBML model. @@ -73,24 +73,30 @@ def mooseReadSBML(filepath, loadpath, solver='ee', validate="on"): """ global sbmlImport_ if sbmlImport_: - modelpath = _readSBML.mooseReadSBML(filepath, loadpath, solver, validate) + modelpath = _readSBML.mooseReadSBML(filepath, loadpath, solver, + validate) sc = solver.lower() - if sc in ["gssa","gillespie","stochastic","gsolve"]: + if sc in ["gssa", "gillespie", "stochastic", "gsolve"]: method = "gssa" - elif sc in ["gsl","runge kutta","deterministic","ksolve","rungekutta","rk5","rkf","rk"]: + elif sc in [ + "gsl", "runge kutta", "deterministic", "ksolve", "rungekutta", + "rk5", "rkf", "rk" + ]: method = "gsl" - elif sc in ["exponential euler","exponentialeuler","neutral", "ee"]: + elif sc in ["exponential euler", "exponentialeuler", "neutral", "ee"]: method = "ee" else: method = "ee" if method != 'ee': - _chemUtil.add_Delete_ChemicalSolver.mooseAddChemSolver(modelpath[0].path, method) + _chemUtil.add_Delete_ChemicalSolver.mooseAddChemSolver( + modelpath[0].path, method) return modelpath else: - logger_.error( sbmlError_ ) + logger_.error(sbmlError_) return False + def mooseWriteSBML(modelpath, filepath, sceneitems={}): """mooseWriteSBML: Writes loaded model under modelpath to a file in SBML format. @@ -112,7 +118,7 @@ def mooseWriteSBML(modelpath, filepath, sceneitems={}): if sbmlImport_: return _writeSBML.mooseWriteSBML(modelpath, filepath, sceneitems) else: - logger_.error( sbmlError_ ) + logger_.error(sbmlError_) return False @@ -128,10 +134,10 @@ def mooseWriteKkit(modelpath, filepath, sceneitems={}): """ global kkitImport_, kkitImport_err_ if not kkitImport_: - print( '[WARN] Could not import module to enable this function' ) - print( '\tError was %s' % kkitImport_error_ ) + print('[WARN] Could not import module to enable this function') + print('\tError was %s' % kkitImport_error_) return False - return _writeKkit.mooseWriteKkit(modelpath, filepath,sceneitems) + return _writeKkit.mooseWriteKkit(modelpath, filepath, sceneitems) def mooseDeleteChemSolver(modelpath): @@ -145,9 +151,10 @@ def mooseDeleteChemSolver(modelpath): to simulate else default is Exponential Euler (ee) """ if chemImport_: - return _chemUtil.add_Delete_ChemicalSolver.mooseDeleteChemSolver(modelpath) + return _chemUtil.add_Delete_ChemicalSolver.mooseDeleteChemSolver( + modelpath) else: - print( chemError_ ) + print(chemError_) return False @@ -165,37 +172,40 @@ def mooseAddChemSolver(modelpath, solver): Runge Kutta ("gsl") etc. Link to documentation? """ if chemImport_: - chemError_ = _chemUtil.add_Delete_ChemicalSolver.mooseAddChemSolver(modelpath, solver) + chemError_ = _chemUtil.add_Delete_ChemicalSolver.mooseAddChemSolver( + modelpath, solver) return chemError_ else: - print( chemError_ ) + print(chemError_) return False + def mergeChemModel(src, des): """mergeChemModel: Merges two chemical model. File or filepath can be passed source is merged to destination """ #global mergechemImport_ if mergechemImport_: - return _chemMerge.merge.mergeChemModel(src,des) + return _chemMerge.merge.mergeChemModel(src, des) else: return False + # NML2 reader and writer function. -def mooseReadNML2( modelpath, verbose = False ): +def mooseReadNML2(modelpath, verbose=False): """Read NeuroML model (version 2) and return reader object. """ global nml2Import_ if not nml2Import_: - mu.warn( nml2ImportError_ ) - raise RuntimeError( "Could not load NML2 support." ) + raise RuntimeError(nml2ImportError_) - reader = _neuroml2.NML2Reader( verbose = verbose ) - reader.read( modelpath ) + reader = _neuroml2.NML2Reader(verbose=verbose) + reader.read(modelpath) return reader -def mooseWriteNML2( outfile ): - raise NotImplementedError( "Writing to NML2 is not supported yet" ) + +def mooseWriteNML2(outfile): + raise NotImplementedError("Writing to NML2 is not supported yet") def loadModel(filename, modelpath, solverclass="gsl"): @@ -217,32 +227,36 @@ def loadModel(filename, modelpath, solverclass="gsl"): moose.element if succcessful else None. """ - if not os.path.isfile( os.path.realpath(filename) ): - mu.warn( "Model file '%s' does not exists or is not readable." % filename ) + if not os.path.isfile(os.path.realpath(filename)): + mu.warn("Model file '%s' does not exists or is not readable." % + filename) return None extension = os.path.splitext(filename)[1] if extension in [".swc", ".p"]: - return _moose.loadModelInternal(filename, modelpath, "Neutral" ) + return _moose.loadModelInternal(filename, modelpath, "Neutral") if extension in [".g", ".cspace"]: # only if genesis or cspace file and method != ee then only # mooseAddChemSolver is called. ret = _moose.loadModelInternal(filename, modelpath, "ee") sc = solverclass.lower() - if sc in ["gssa","gillespie","stochastic","gsolve"]: + if sc in ["gssa", "gillespie", "stochastic", "gsolve"]: method = "gssa" - elif sc in ["gsl","runge kutta","deterministic","ksolve","rungekutta","rk5","rkf","rk"]: + elif sc in [ + "gsl", "runge kutta", "deterministic", "ksolve", "rungekutta", + "rk5", "rkf", "rk" + ]: method = "gsl" - elif sc in ["exponential euler","exponentialeuler","neutral"]: + elif sc in ["exponential euler", "exponentialeuler", "neutral"]: method = "ee" else: method = "ee" if method != 'ee': - _chemUtil.add_Delete_ChemicalSolver.mooseAddChemSolver(modelpath, method) + _chemUtil.add_Delete_ChemicalSolver.mooseAddChemSolver( + modelpath, method) return ret else: - logger_.error( "Unknown model extenstion '%s'" % extension) + logger_.error("Unknown model extenstion '%s'" % extension) return None - diff --git a/python/moose/neuroml2/__main__.py b/python/moose/neuroml2/__main__.py new file mode 100644 index 0000000000..274fba633c --- /dev/null +++ b/python/moose/neuroml2/__main__.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- + +# WARNING: This is for debuging purpose and should not be used in production. +# Quickly load neuroml2 into MOOSE. + + +__author__ = "Dilawar Singh" +__copyright__ = "Copyright 2019-, Dilawar Singh" +__maintainer__ = "Dilawar Singh" +__email__ = "dilawars@ncbs.res.in" + +import moose + +import logging +logger_ = logging.getLogger('moose.nml2') + +def _addStreamer(): + logger_.warning('TODO. Add streamer.') + + +def main(**kwargs): + logger_.info("Reading file %s" % kwargs['nml2file']) + moose.mooseReadNML2(kwargs['nml2file']) + _addStreamer() + moose.reinit() + simtime = kwargs['runtime'] + moose.start(simtime) + logger_.info("All done") + +if __name__ == '__main__': + import argparse + # Argument parser. + description = '''Load neuroml2 model into moose.''' + parser = argparse.ArgumentParser(description=description) + parser.add_argument('nml2file', help = 'Neuroml2 file.' + , metavar="" + ) + parser.add_argument('--output', '-o' + , required = False + , help = 'Output file' + ) + parser.add_argument('--runtime', '-T' + , required = False, default = 1.0, type=float + , help = 'Simulation time (sec)' + ) + + parser.add_argument('--debug', '-d' + , required = False + , default = 0 + , type = int + , help = 'Enable debug mode. Default 0, debug level' + ) + class Args: pass + args = Args() + parser.parse_args(namespace=args) + main(**vars(args)) diff --git a/python/moose/neuroml2/reader.py b/python/moose/neuroml2/reader.py index 8140e8c536..ce8e9f251e 100644 --- a/python/moose/neuroml2/reader.py +++ b/python/moose/neuroml2/reader.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -from __future__ import print_function, division, absolute_import # Description: NeuroML2 reader. # Implementation of reader for NeuroML 2 models. @@ -9,64 +8,97 @@ # Maintainer: Dilawar Singh # Created: Wed Jul 24 15:55:54 2013 (+0530) # -# Notes: -# For update/log, please see git-blame documentation or browse the github +# Notes: +# For update/log, please see git-blame documentation or browse the github # repo https://github.com/BhallaLab/moose-core -import os import math import numpy as np +from moose.neuroml2.hhfit import exponential2 +from moose.neuroml2.hhfit import sigmoid2 +from moose.neuroml2.hhfit import linoid2 +from moose.neuroml2.units import SI import moose import logging -logger_ = logging.getLogger('moose.nml2') -import neuroml as nml -import pyneuroml.pynml as pynml -from moose.neuroml2.units import SI +logger_ = logging.getLogger("moose.nml2") +logger_.setLevel(logging.INFO) + +try: + import neuroml.loaders as loaders + from pyneuroml import pynml +except Exception as e: + print(e) + print("********************************************************************") + print("* ") + print("* Please install libNeuroML & pyNeuroML: ") + print("* pip install libneuroml") + print("* pip install pyNeuroML") + print("* ") + print("* Requirement for this is lxml: ") + print("* apt-get install python-lxml") + print("* ") + print("********************************************************************") + +# these are the gates available. These are prefixed by 'gate' in C++ codebase. +_validMooseHHGateIds = ["X", "Y", "Z"] + + +def _unique(ls): + res = [] + for l in ls: + if l not in res: + res.append(l) + return res -def _write_flattened_nml( doc, outfile ): - """_write_flattened_nml - Concat all NML2 read by moose and generate one flattened NML file. - Only useful when debugging. - :param doc: NML document (nml.doc) - :param outfile: Name of the output file. - """ - import neuroml.writers - neuroml.writers.NeuroMLWriter.write( doc, outfile ) - logger_.debug( "Wrote flattened NML model to %s" % outfile ) +def _whichGate(chan): + global _validMooseHHGateIds + c = chan.name[-1] + assert c in _validMooseHHGateIds + return c -def _gates_sorted( all_gates ): - """_gates_sorted +def _setAttrFromNMLAttr(mObj, mAttr, nObj, nAttr, convertToSI=False): + """Set MOOSE's object attribute from NML attribute - Parameters - ---------- - all_gates (list) - List of all moose.HHChannel.gates - - Notes - ----- - If the id of gates are subset of 'x', 'y' or 'z' then sort them so they load in - X, Y or Z gate respectively. Otherwise do not touch them i.e. first gate - will be loaded into X, second into Y and so on. + :param mObj: MOOSE object. + :param mAttr: MOOSE object's attribute + :param nObj: NML2 Object + :param nAttr: NML2 Object attribute. + :param convertToSI: If `True` convert value to si unit. """ - allMooseGates = ['x', 'y', 'z'] - allGatesDict = { g.id : g for g in all_gates } - gateNames = [ g.id.lower() for g in all_gates ] - if set(gateNames).issubset(set(allMooseGates)): - sortedGates = [] - for gid in allMooseGates: - sortedGates.append( allGatesDict.get(gid) ) - return sortedGates - return all_gates - -def _unique( ls ): - res = [ ] - for l in ls: - if l not in res: - res.append( l ) - return res + if not hasattr(nObj, nAttr): + return + if not hasattr(mObj, mAttr): + return + val = SI(getattr(nObj, nAttr)) if convertToSI else getattr(nObj, nAttr) + setattr(mObj, mAttr, val) + +def _pairNmlGateWithMooseGates(mGates, nmlGates): + """Return moose gate id from nml.HHGate + """ + global _validMooseHHGateIds + # deep copy + mooseGatesMap = {_whichGate(x): x for x in mGates} + availableMooseGates = _validMooseHHGateIds[:] + mapping = {} + for nmlGate in nmlGates: + if nmlGate is None: + continue + if ( + hasattr(nmlGate, "id") + and nmlGate.id + and nmlGate.id.upper() in availableMooseGates + ): + mapping[nmlGate.id.upper()] = nmlGate + availableMooseGates.remove(nmlGate.id.upper()) + else: + mapping[availableMooseGates.pop(0)] = nmlGate + + # Now replace 'X', 'Y', 'Z' with moose gates. + return [(mooseGatesMap[x], mapping[x]) for x in mapping] + def _isConcDep(ct): """_isConcDep @@ -78,48 +110,52 @@ def _isConcDep(ct): :return: True if Component is depenant on conc, False otherwise. """ - if 'ConcDep' in ct.extends: + if not hasattr(ct, "extends"): + return False + if "ConcDep" in ct.extends: return True return False -def _findCaConcVariableName(): - """_findCaConcVariableName + +def _findCaConc(): + """_findCaConc Find a suitable CaConc for computing HHGate tables. This is a hack, though it is likely to work in most cases. """ - caConcs = moose.wildcardFind( '/library/##[TYPE=CaConc]' ) - assert len(caConcs) >= 1, "No moose.CaConc found. Currently moose \ - supports HHChannel which depends only on moose.CaConc ." - return caConcs[0].name + caConcs = moose.wildcardFind("/library/##[TYPE=CaConc]") + assert len(caConcs) == 1, "No moose.CaConc found." + \ + " Currently moose supports HHChannel which depends only " + \ + " on moose.CaConc. %s" % str(caConcs) + return caConcs[0] + def sarea(comp): - """sarea - Return the surface area (2ϖrL) of compartment from length and diameter. + """ + Return the surface area of compartment from length and + diameter. + + Parameters + ---------- + comp : Compartment instance. + + Returns + ------- + s : float + surface area of `comp`. - :param comp: Compartment instance. - :type comp: str - :return: surface area of `comp`. - :rtype: float """ if comp.length > 0: - return math.pi * comp.diameter * comp.length + return comp.length * comp.diameter * np.pi else: - return math.pi * comp.diameter * comp.diameter + return comp.diameter * comp.diameter * np.pi -def xarea(compt): - """xarea - Return the cross sectional area (𝜋r²) from the diameter of the compartment. - Note: - ---- - How to do it for spherical compartment? - - :param compt: Compartment in moose. - :type compt: moose.Compartment - :return: cross sectional area. - :rtype: float +def xarea(comp): """ - return math.pi * (compt.diameter/2.0)**2.0 + Return the cross sectional area from diameter of the + compartment. How to do it for spherical compartment?""" + return comp.diameter * comp.diameter * np.pi / 4.0 + def setRa(comp, resistivity): """Calculate total raxial from specific value `resistivity`""" @@ -128,24 +164,35 @@ def setRa(comp, resistivity): else: comp.Ra = resistivity * 8.0 / (comp.diameter * np.pi) + def setRm(comp, condDensity): """Set membrane resistance""" - comp.Rm = 1/(condDensity * sarea(comp)) + comp.Rm = 1 / (condDensity * sarea(comp)) + def setEk(comp, erev): """Set reversal potential""" comp.setEm(erev) + def getSegments(nmlcell, component, sg_to_segments): """Get the list of segments the `component` is applied to""" sg = component.segment_groups + # seg = component.segment if sg is None: segments = nmlcell.morphology.segments - elif sg == 'all': + elif sg == "all": # Special case segments = [seg for seglist in sg_to_segments.values() for seg in seglist] else: segments = sg_to_segments[sg] - return _unique(segments) + + unique_segs = [] + unique_segs_ids = [] + for s in segments: + if not s.id in unique_segs_ids: + unique_segs.append(s) + unique_segs_ids.append(s.id) + return unique_segs class NML2Reader(object): @@ -156,127 +203,202 @@ class NML2Reader(object): Example: - >>> import moose - >>> reader = moose.NML2Reader() + >>> from moose import neuroml2 as nml + >>> reader = nml.NML2Reader() >>> reader.read('moose/neuroml2/test_files/Purk2M9s.nml') creates a passive neuronal morphology `/library/Purk2M9s`. """ + def __init__(self, verbose=False): - global logger_ - self.lunit = 1e-6 # micron is the default length unit + # micron is the default length unit + self.lunit = 1e-6 + self.verbose = verbose - if self.verbose: - logger_.setLevel( logging.DEBUG ) self.doc = None - self.filename = None - self.nml_to_moose = {} # NeuroML object to MOOSE object - self.moose_to_nml = {} # Moose object to NeuroML object + self.filename = None + + self.nml_cells_to_moose = {} # NeuroML object to MOOSE object + self.nml_segs_to_moose = {} # NeuroML object to MOOSE object + self.nml_chans_to_moose = {} # NeuroML object to MOOSE object + self.nml_concs_to_moose = {} # NeuroML object to MOOSE object + self.moose_to_nml = {} # Moose object to NeuroML object self.proto_cells = {} # map id to prototype cell in moose self.proto_chans = {} # map id to prototype channels in moose self.proto_pools = {} # map id to prototype pools (Ca2+, Mg2+) - self.includes = {} # Included files mapped to other readers - self.lib = moose.element('/library') if moose.exists('/library') \ - else moose.Neutral( '/library' ) + self.includes = {} # Included files mapped to other readers + + # /library may have alreay been created. + if moose.exists("/library"): + self.lib = moose.element("/library") + else: + self.lib = moose.Neutral("/library") + self.id_to_ionChannel = {} - self._cell_to_sg = {} # nml cell to dict - the dict maps segment groups to segments - self._variables = {} - + + # nml cell to dict - the dict maps segment groups to segments + self._cell_to_sg = {} + self.cells_in_populations = {} self.pop_to_cell_type = {} self.seg_id_to_comp_name = {} self.paths_to_chan_elements = {} - self.network = None + + # Just in case. + self._variables = {} def read(self, filename, symmetric=True): - filename = os.path.realpath( filename ) - self.doc = nml.loaders.read_neuroml2_file( - filename, include_includes=True, verbose=self.verbose) - - self.filename = filename + self.doc = loaders.read_neuroml2_file( + filename, include_includes=True, verbose=self.verbose + ) - logger_.info('Parsed NeuroML2 file: %s'% filename) if self.verbose: - _write_flattened_nml( self.doc, '%s__flattened.xml' % self.filename ) - - if len(self.doc.networks)>=1: + print("Parsed NeuroML2 file: %s" % filename) + self.filename = filename + + if len(self.doc.networks) >= 1: self.network = self.doc.networks[0] + moose.celsius = self._getTemperature() - + self.importConcentrationModels(self.doc) self.importIonChannels(self.doc) self.importInputs(self.doc) - + for cell in self.doc.cells: self.createCellPrototype(cell, symmetric=symmetric) - - if len(self.doc.networks)>=1: + + for iaf in self.doc.iaf_cells: + self.createIAFCellPrototype(iaf) + + if len(self.doc.networks) >= 1: self.createPopulations() self.createInputs() - + print("Read all from %s" % filename) + def _getTemperature(self): - if self.network is not None: - if self.network.type=="networkWithTemperature": - return SI(self.network.temperature) - else: - # Why not, if there's no temp dependence in nml..? - return 0 - return SI('25') - + if self.network.type == "networkWithTemperature": + return SI(self.network.temperature) + else: + return 0 # Why not, if there's no temp dependence in nml..? + def getCellInPopulation(self, pop_id, index): return self.cells_in_populations[pop_id][index] - + def getComp(self, pop_id, cellIndex, segId): - return moose.element('%s/%s/%s/%s' % ( self.lib.path, pop_id, cellIndex - , self.seg_id_to_comp_name[self.pop_to_cell_type[pop_id]][segId]) + if pop_id not in self.pop_to_cell_type: + logger_.error("%s is not in populations: %s" % (pop_id + , str(list(self.pop_to_cell_type.keys())))) + raise LookupError("%s not found" % pop_id) + + cellType = self.pop_to_cell_type[pop_id] + if cellType not in self.seg_id_to_comp_name: + logger_.error("%s not found in %s.compartments: %s" % (cellType + , pop_id, str(list(self.seg_id_to_comp_name.keys())))) + raise LookupError("%s not found" % cellType) + + compt = self.seg_id_to_comp_name[cellType] + if segId not in compt: + logger_.error("%s not found in %s.%s.segments: %s" % (compt + , pop_id, cellType, str(list(compt.keys())))) + raise LookupError("%s not found" % segId) + return moose.element( + "%s/%s/%s/%s" + % ( + self.lib.path, + pop_id, + cellIndex, + self.seg_id_to_comp_name[self.pop_to_cell_type[pop_id]][segId], ) - + ) + def createPopulations(self): for pop in self.network.populations: - ep = '%s/%s' % (self.lib.path, pop.id) - mpop = moose.element(ep) if moose.exists(ep) else moose.Neutral(ep) - self.cells_in_populations[pop.id] ={} + # Sometime NML2 returns None instead of 0 + logger_.info("Adding population %s" % pop) + pop.size = 0 if pop.size is None else pop.size + mpop = moose.Neutral("%s/%s" % (self.lib.path, pop.id)) + self.cells_in_populations[pop.id] = {} + + # Either population have size of instances for i in range(pop.size): - logger_.info("Creating %s/%s instances of %s under %s"%(i,pop.size,pop.component, mpop)) - self.pop_to_cell_type[pop.id]=pop.component - chid = moose.copy(self.proto_cells[pop.component], mpop, '%s'%(i)) - self.cells_in_populations[pop.id][i]=chid - - + self.pop_to_cell_type[pop.id] = pop.component + chid = moose.copy(self.proto_cells[pop.component], mpop, "%d"%i) + self.cells_in_populations[pop.id][i] = chid + logger_.info("Created %s instances of %s (Type %s)" + % (chid, pop.id, pop.component) + ) + + # Add instance of population. + for i, instance in enumerate(pop.instances): + self.pop_to_cell_type[pop.id] = pop.component + chid = moose.copy(self.proto_cells[pop.component], mpop, '%d'%instance.id) + self.cells_in_populations[pop.id][instance.id] = chid + logger_.info("Created %s instances of %s (Type %s)" + % (chid, pop.id, pop.component) + ) + def getInput(self, input_id): - return moose.element('%s/inputs/%s'%(self.lib.path,input_id)) - - + return moose.element("%s/inputs/%s" % (self.lib.path, input_id)) + def createInputs(self): for el in self.network.explicit_inputs: - pop_id = el.target.split('[')[0] - i = el.target.split('[')[1].split(']')[0] + pop_id = el.target.split("[")[0] + i = el.target.split("[")[1].split("]")[0] seg_id = 0 - if '/' in el.target: - seg_id = el.target.split('/')[1] + if "/" in el.target: + seg_id = el.target.split("/")[1] input = self.getInput(el.input) - moose.connect(input, 'output', self.getComp(pop_id,i,seg_id), 'injectMsg') - + moose.connect(input, "output", self.getComp(pop_id, i, seg_id), "injectMsg") + for il in self.network.input_lists: for ii in il.input: input = self.getInput(il.component) - moose.connect(input, 'output' - , self.getComp(il.populations,ii.get_target_cell__hash(),ii.get_segment__hash()) - , 'injectMsg') - + moose.connect( + input, + "output", + self.getComp( + il.populations, ii.get_target_cell_id(), ii.get_segment_id() + ), + "injectMsg", + ) + + def createIAFCellPrototype(self, iaf): + """FIXME: Not tested. + """ + mLIF = moose.LIF("%s/%s" % (self.lib.path, iaf.id)) + _setAttrFromNMLAttr(mLIF, 'vReset', iaf, 'reset', True) + _setAttrFromNMLAttr(mLIF, 'thres', iaf, 'thres', True) + _setAttrFromNMLAttr(mLIF, 'refractoryPeriod', iaf, 'refrac', True) + _setAttrFromNMLAttr(mLIF, 'Cm', iaf, 'C', True) + _setAttrFromNMLAttr(mLIF, 'Ra', iaf, 'Ra', True) + + if iaf.leak_conductance: + mLIF.Rm = 1.0/SI(iaf.leak_conductance) + + if hasattr(iaf, 'leak_reversal'): + logger_.warning("moose.LIF does not supprot 'leakReversal' ") + + self.proto_cells[iaf.id] = mLIF + self.nml_cells_to_moose[iaf.id] = mLIF + self.moose_to_nml[mLIF] = iaf + + # IAF cells have no morphology. Only one element. We need to create an element which + # can recieve input. + self.seg_id_to_comp_name[iaf.id] = {0:''} + + return iaf, mLIF def createCellPrototype(self, cell, symmetric=True): """To be completed - create the morphology, channels in prototype""" - ep = '%s/%s' % (self.lib.path, cell.id) - nrn = moose.element(ep) if moose.exists(ep) else moose.Neuron(ep) + nrn = moose.Neuron("%s/%s" % (self.lib.path, cell.id)) self.proto_cells[cell.id] = nrn - self.nml_to_moose[cell.id] = nrn + self.nml_cells_to_moose[cell.id] = nrn self.moose_to_nml[nrn] = cell self.createMorphology(cell, nrn, symmetric=symmetric) self.importBiophysics(cell, nrn) return cell, nrn - def createMorphology(self, nmlcell, moosecell, symmetric=True): """Create the MOOSE compartmental morphology in `moosecell` using the segments in NeuroML2 cell `nmlcell`. Create symmetric @@ -284,8 +406,13 @@ def createMorphology(self, nmlcell, moosecell, symmetric=True): """ morphology = nmlcell.morphology + if morphology is None: + logger_.warning("%s has no morphology?" % nmlcell) + return + segments = morphology.segments - id_to_segment = dict([(seg.id, seg) for seg in segments]) + + id_to_segment = dict([(seg.id, seg) for seg in segments]) if symmetric: compclass = moose.SymCompartment else: @@ -294,22 +421,20 @@ def createMorphology(self, nmlcell, moosecell, symmetric=True): # naming convention does not clash with that in MOOSE cellpath = moosecell.path id_to_comp = {} - self.seg_id_to_comp_name[nmlcell.id]={} + self.seg_id_to_comp_name[nmlcell.id] = {} for seg in segments: if seg.name is not None: - ep = '%s/%s' % (cellpath, seg.name) - id_to_comp[seg.id] = moose.element(ep) if moose.exists(ep) else compclass(ep) + id_to_comp[seg.id] = compclass("%s/%s" % (cellpath, seg.name)) self.seg_id_to_comp_name[nmlcell.id][seg.id] = seg.name else: - name = 'comp_%s'%seg.id - ep = '%s/%s' % (cellpath, name) - id_to_comp[seg.id] = moose.element(ep) if moose.exists(ep) else compclass(ep) + name = "comp_%s" % seg.id + id_to_comp[seg.id] = compclass("%s/%s" % (cellpath, name)) self.seg_id_to_comp_name[nmlcell.id][seg.id] = name # Now assign the positions and connect up axial resistance if not symmetric: - src, dst = 'axial', 'raxial' + src, dst = "axial", "raxial" else: - src, dst = 'proximal', 'distal' + src, dst = "proximal", "distal" for segid, comp in id_to_comp.items(): segment = id_to_segment[segid] try: @@ -317,29 +442,36 @@ def createMorphology(self, nmlcell, moosecell, symmetric=True): except AttributeError: parent = None self.moose_to_nml[comp] = segment - self.nml_to_moose[segment.id] = comp - p0 = segment.proximal + self.nml_segs_to_moose[segment.id] = comp + p0 = segment.proximal if p0 is None: if parent: p0 = parent.distal else: raise Exception( - 'No proximal point and no parent segment for segment:'+\ - 'name=%s, id=%s' % (segment.name, segment.id) - ) - comp.x0, comp.y0, comp.z0 = (x*self.lunit for x in map(float, (p0.x, p0.y, p0.z))) + "No proximal point and no parent segment for segment: name=%s, id=%s" + % (segment.name, segment.id) + ) + comp.x0, comp.y0, comp.z0 = ( + x * self.lunit for x in map(float, (p0.x, p0.y, p0.z)) + ) p1 = segment.distal - comp.x, comp.y, comp.z = (x*self.lunit for x in map(float, (p1.x, p1.y, p1.z))) - comp.length = np.sqrt((comp.x-comp.x0)**2+(comp.y-comp.y0)**2+(comp.z-comp.z0)**2) - + comp.x, comp.y, comp.z = ( + x * self.lunit for x in map(float, (p1.x, p1.y, p1.z)) + ) + comp.length = np.sqrt( + (comp.x - comp.x0) ** 2 + + (comp.y - comp.y0) ** 2 + + (comp.z - comp.z0) ** 2 + ) # This can pose problem with moose where both ends of # compartment have same diameter. We are averaging the two # - may be splitting the compartment into two is better? - comp.diameter = (float(p0.diameter)+float(p1.diameter)) * self.lunit / 2 + comp.diameter = (float(p0.diameter) + float(p1.diameter)) * self.lunit / 2 if parent: pcomp = id_to_comp[parent.id] moose.connect(comp, src, pcomp, dst) - sg_to_segments = {} + sg_to_segments = {} for sg in morphology.segment_groups: sg_to_segments[sg.id] = [id_to_segment[m.segments] for m in sg.members] for sg in morphology.segment_groups: @@ -348,10 +480,10 @@ def createMorphology(self, nmlcell, moosecell, symmetric=True): for inc in sg.includes: for cseg in sg_to_segments[inc.segment_groups]: sg_to_segments[sg.id].append(cseg) - - if not 'all' in sg_to_segments: - sg_to_segments['all'] = [ s for s in segments ] - + + if not "all" in sg_to_segments: + sg_to_segments["all"] = [s for s in segments] + self._cell_to_sg[nmlcell.id] = sg_to_segments return id_to_comp, id_to_segment, sg_to_segments @@ -360,15 +492,20 @@ def importBiophysics(self, nmlcell, moosecell): according to NeuroML2 cell `nmlcell`.""" bp = nmlcell.biophysical_properties if bp is None: - logger_.info('Warning: %s in %s has no biophysical properties' % (nmlcell.id, self.filename)) + print( + "Warning: %s in %s has no biophysical properties" + % (nmlcell.id, self.filename) + ) return self.importMembraneProperties(nmlcell, moosecell, bp.membrane_properties) - self.importIntracellularProperties(nmlcell, moosecell, bp.intracellular_properties) + self.importIntracellularProperties( + nmlcell, moosecell, bp.intracellular_properties + ) def importMembraneProperties(self, nmlcell, moosecell, mp): """Create the membrane properties from nmlcell in moosecell""" if self.verbose: - logger_.info('Importing membrane properties') + print("Importing membrane properties") self.importCapacitances(nmlcell, moosecell, mp.specific_capacitances) self.importChannelsToCell(nmlcell, moosecell, mp) self.importInitMembPotential(nmlcell, moosecell, mp) @@ -378,16 +515,16 @@ def importCapacitances(self, nmlcell, moosecell, specificCapacitances): for specific_cm in specificCapacitances: cm = SI(specific_cm.value) for seg in sg_to_segments[specific_cm.segment_groups]: - comp = self.nml_to_moose[seg.id] + comp = self.nml_segs_to_moose[seg.id] comp.Cm = sarea(comp) * cm - + def importInitMembPotential(self, nmlcell, moosecell, membraneProperties): sg_to_segments = self._cell_to_sg[nmlcell.id] for imp in membraneProperties.init_memb_potentials: initv = SI(imp.value) for seg in sg_to_segments[imp.segment_groups]: - comp = self.nml_to_moose[seg.id] - comp.initVm = initv + comp = self.nml_segs_to_moose[seg.id] + comp.initVm = initv def importIntracellularProperties(self, nmlcell, moosecell, properties): self.importAxialResistance(nmlcell, properties) @@ -396,40 +533,39 @@ def importIntracellularProperties(self, nmlcell, moosecell, properties): def importSpecies(self, nmlcell, properties): sg_to_segments = self._cell_to_sg[nmlcell.id] for species in properties.species: - # Developer note: Not sure if species.concentration_model should be - # a nml element of just plain string. I was getting plain text from - # nml file here. - concModel = species.concentration_model - if (concModel is not None) and (concModel not in self.proto_pools): - logger_.warn("No concentrationModel '%s' found."%concModel) + if (species.concentration_model is not None) and ( + species.concentration_model not in self.proto_pools + ): continue segments = getSegments(nmlcell, species, sg_to_segments) for seg in segments: - comp = self.nml_to_moose[seg.id] + comp = self.nml_segs_to_moose[seg.id] self.copySpecies(species, comp) def copySpecies(self, species, compartment): """Copy the prototype pool `species` to compartment. Currently only decaying pool of Ca2+ supported""" proto_pool = None - concModel = species.concentration_model - if concModel in self.proto_pools: - proto_pool = self.proto_pools[concModel] + if species.concentration_model in self.proto_pools: + proto_pool = self.proto_pools[species.concentration_model] else: for innerReader in self.includes.values(): - if concModel in innerReader.proto_pools: - proto_pool = innerReader.proto_pools[concModel] + if species.concentration_model in innerReader.proto_pools: + proto_pool = innerReader.proto_pools[species.concentration_model] break if not proto_pool: - msg = 'No prototype pool for %s referred to by %s' % (concModel, species.id) - logger_.error(msg) - raise RuntimeError(msg) + raise Exception( + "No prototype pool for %s referred to by %s" + % (species.concentration_model, species.id) + ) pool_id = moose.copy(proto_pool, compartment, species.id) pool = moose.element(pool_id) - pool.B = pool.B / (np.pi * compartment.length * ( - 0.5 * compartment.diameter + pool.thick) * - (0.5 * compartment.diameter - pool.thick) - ) + pool.B = pool.B / ( + np.pi + * compartment.length + * (0.5 * compartment.diameter + pool.thick) + * (0.5 * compartment.diameter - pool.thick) + ) return pool def importAxialResistance(self, nmlcell, intracellularProperties): @@ -437,92 +573,127 @@ def importAxialResistance(self, nmlcell, intracellularProperties): for r in intracellularProperties.resistivities: segments = getSegments(nmlcell, r, sg_to_segments) for seg in segments: - comp = self.nml_to_moose[seg.id] - setRa(comp, SI(r.value)) - - def isPassiveChan(self,chan): - if chan.type == 'ionChannelPassive': + comp = self.nml_segs_to_moose[seg.id] + setRa(comp, SI(r.value)) + + def isPassiveChan(self, chan): + if chan.type == "ionChannelPassive": return True - if hasattr(chan,'gates'): - return len(chan.gate_hh_rates)+len(chan.gates)==0 + if hasattr(chan, "gates"): + return len(chan.gate_hh_rates) + len(chan.gates) == 0 return False - def evaluate_moose_component(self, ct, variables): - print( "[INFO ] Not implemented." ) - return False - - def calculateRateFn(self, ratefn, vmin, vmax, tablen=3000, vShift='0mV'): - """Returns A / B table from ngate.""" - from . import hhfit + rate_fn_map = { + "HHExpRate": exponential2, + "HHSigmoidRate": sigmoid2, + "HHSigmoidVariable": sigmoid2, + "HHExpLinearRate": linoid2, + } - rate_fn_map = { - 'HHExpRate': hhfit.exponential2, - 'HHSigmoidRate': hhfit.sigmoid2, - 'HHSigmoidVariable': hhfit.sigmoid2, - 'HHExpLinearRate': hhfit.linoid2 - } + def calculateRateFn(self, ratefn, mgate, vmin, vmax, tablen=3000, vShift="0mV"): + """Returns A / B table from ngate.""" tab = np.linspace(vmin, vmax, tablen) if self._is_standard_nml_rate(ratefn): - midpoint, rate, scale = map(SI, (ratefn.midpoint, ratefn.rate, ratefn.scale)) - return rate_fn_map[ratefn.type](tab, rate, scale, midpoint) + midpoint, rate, scale = map( + SI, (ratefn.midpoint, ratefn.rate, ratefn.scale) + ) + return self.rate_fn_map[ratefn.type](tab, rate, scale, midpoint) for ct in self.doc.ComponentType: if ratefn.type != ct.name: continue - - logger_.info("Using %s to evaluate rate"%ct.name) - rate = [] - for v in tab: - # Note: MOOSE HHGate are either voltage of concentration - # dependant. Here we figure out if nml description of gate is - # concentration dependant or note. - if _isConcDep(ct): - # Concentration dependant. Concentration can't be negative. - # Find a suitable CaConc from the /library. Currently on Ca - # dependant channels are allowed. - caConcName = _findCaConcVariableName() - req_vars = {caConcName:'%g'%max(0,v),'vShift':vShift,'temperature':self._getTemperature()} - else: - req_vars = {'v':'%sV'%v,'vShift':vShift,'temperature':self._getTemperature()} - req_vars.update( self._variables ) - vals = pynml.evaluate_component(ct, req_variables=req_vars) - v = vals.get('x', vals.get('t', vals.get('r', None))) - if v is not None: - rate.append(v) - return np.array(rate) - - print( "[WARN ] Could not determine rate: %s %s %s" %(ratefn.type,vmin,vmax)) - return np.array([]) - + logger_.info("Using %s to evaluate rate" % ct.name) + if not _isConcDep(ct): + return self._computeRateFn(ct, tab) + else: + ca = _findCaConc() + if _whichGate(mgate) != "Z": + raise RuntimeWarning( + "Concentration dependant gate " + " should use gateZ of moose.HHChannel. " + " If you know what you are doing, ignore this " + " warning. " + ) + return self._computeRateFnCa(ca, ct, tab, vShift=vShift) + + def _computeRateFnCa(self, ca, ct, tab, vShift): + rate = [] + for v in tab: + req_vars = { + ca.name: "%sV" % v, + "vShift": vShift, + "temperature": self._getTemperature(), + } + req_vars.update(self._variables) + vals = pynml.evaluate_component(ct, req_variables=req_vars) + """print(vals)""" + if "x" in vals: + rate.append(vals["x"]) + if "t" in vals: + rate.append(vals["t"]) + if "r" in vals: + rate.append(vals["r"]) + return np.array(rate) + + def _computeRateFn(self, ct, tab, vShift=0): + rate = [] + for v in tab: + req_vars = { + "v": "%sV" % v, + "vShift": vShift, + "temperature": self._getTemperature(), + } + req_vars.update(self._variables) + vals = pynml.evaluate_component(ct, req_variables=req_vars) + """print(vals)""" + if "x" in vals: + rate.append(vals["x"]) + if "t" in vals: + rate.append(vals["t"]) + if "r" in vals: + rate.append(vals["r"]) + return np.array(rate) def importChannelsToCell(self, nmlcell, moosecell, membrane_properties): sg_to_segments = self._cell_to_sg[nmlcell.id] - for chdens in membrane_properties.channel_densities + membrane_properties.channel_density_v_shifts: + for chdens in ( + membrane_properties.channel_densities + + membrane_properties.channel_density_v_shifts + ): segments = getSegments(nmlcell, chdens, sg_to_segments) condDensity = SI(chdens.cond_density) erev = SI(chdens.erev) try: ionChannel = self.id_to_ionChannel[chdens.ion_channel] except KeyError: - logger_.info('No channel with id: %s' % chdens.ion_channel) + print("No channel with id", chdens.ion_channel) continue - + if self.verbose: - logger_.info('Setting density of channel %s in %s to %s; erev=%s (passive: %s)'%( - chdens.id, segments, condDensity,erev,self.isPassiveChan(ionChannel)) + print( + "Setting density of channel %s in %s to %s; erev=%s (passive: %s)" + % ( + chdens.id, + segments, + condDensity, + erev, + self.isPassiveChan(ionChannel), ) - + ) + if self.isPassiveChan(ionChannel): for seg in segments: - # comp = self.nml_to_moose[seg] - setRm(self.nml_to_moose[seg.id], condDensity) - setEk(self.nml_to_moose[seg.id], erev) + comp = self.nml_segs_to_moose[seg.id] + setRm(comp, condDensity) + setEk(comp, erev) else: for seg in segments: - self.copyChannel(chdens, self.nml_to_moose[seg.id], condDensity, erev) - '''moose.le(self.nml_to_moose[seg]) - moose.showfield(self.nml_to_moose[seg], field="*", showtype=True)''' + self.copyChannel( + chdens, self.nml_segs_to_moose[seg.id], condDensity, erev + ) + """moose.le(self.nml_segs_to_moose[seg.id]) + moose.showfield(self.nml_segs_to_moose[seg.id], field="*", showtype=True)""" def copyChannel(self, chdens, comp, condDensity, erev): """Copy moose prototype for `chdens` condutcance density to `comp` @@ -538,173 +709,250 @@ def copyChannel(self, chdens, comp, condDensity, erev): proto_chan = innerReader.proto_chans[chdens.ion_channel] break if not proto_chan: - raise Exception('No prototype channel for %s referred to by %s' % (chdens.ion_channel, chdens.id)) + raise Exception( + "No prototype channel for %s referred to by %s" + % (chdens.ion_channel, chdens.id) + ) if self.verbose: - logger_.info('Copying %s to %s, %s; erev=%s'%(chdens.id, comp, condDensity, erev)) + print( + "Copying %s to %s, %s; erev=%s" % (chdens.id, comp, condDensity, erev) + ) orig = chdens.id chid = moose.copy(proto_chan, comp, chdens.id) chan = moose.element(chid) - - # We are updaing the keys() here. Need copy: using list(keys()) to - # create a copy. - for p in list(self.paths_to_chan_elements.keys()): - pp = p.replace('%s/'%chdens.ion_channel,'%s/'%orig) - self.paths_to_chan_elements[pp] = self.paths_to_chan_elements[p].replace('%s/'%chdens.ion_channel,'%s/'%orig) - #logger_.info(self.paths_to_chan_elements) + els = list(self.paths_to_chan_elements.keys()) + for p in els: + pp = p.replace("%s/" % chdens.ion_channel, "%s/" % orig) + self.paths_to_chan_elements[pp] = self.paths_to_chan_elements[p].replace( + "%s/" % chdens.ion_channel, "%s/" % orig + ) + # print(self.paths_to_chan_elements) chan.Gbar = sarea(comp) * condDensity chan.Ek = erev - moose.connect(chan, 'channel', comp, 'channel') - return chan + moose.connect(chan, "channel", comp, "channel") + return chan + + """ + def importIncludes(self, doc): + for include in doc.include: + if self.verbose: + print(self.filename, 'Loading include', include) + error = None + inner = NML2Reader(self.verbose) + paths = [include.href, os.path.join(os.path.dirname(self.filename), include.href)] + for path in paths: + try: + inner.read(path) + if self.verbose: + print(self.filename, 'Loaded', path, '... OK') + except IOError as e: + error = e + else: + self.includes[include.href] = inner + self.id_to_ionChannel.update(inner.id_to_ionChannel) + self.nml_to_moose.update(inner.nml_to_moose) + self.moose_to_nml.update(inner.moose_to_nml) + error = None + break + if error: + print(self.filename, 'Last exception:', error) + raise IOError('Could not read any of the locations: %s' % (paths))""" def _is_standard_nml_rate(self, rate): - return rate.type=='HHExpLinearRate' \ - or rate.type=='HHExpRate' or \ - rate.type=='HHSigmoidRate' or \ - rate.type=='HHSigmoidVariable' + return ( + rate.type == "HHExpLinearRate" + or rate.type == "HHExpRate" + or rate.type == "HHSigmoidRate" + or rate.type == "HHSigmoidVariable" + ) def createHHChannel(self, chan, vmin=-150e-3, vmax=100e-3, vdivs=5000): - mchan = moose.HHChannel('%s/%s' % (self.lib.path, chan.id)) - mgates = [moose.element(x) for x in [mchan.gateX, mchan.gateY, mchan.gateZ]] - assert len(chan.gate_hh_rates)<=3, "We handle only up to 3 gates in HHCHannel" - + path = "%s/%s" % (self.lib.path, chan.id) + if moose.exists(path): + mchan = moose.element(path) + else: + mchan = moose.HHChannel(path) + mgates = [moose.element(g) for g in [mchan.gateX, mchan.gateY, mchan.gateZ]] + + # We handle only up to 3 gates in HHCHannel + assert len(chan.gate_hh_rates) <= 3, "No more than 3 gates" + if self.verbose: - logger_.info('== Creating channel: %s (%s) -> %s (%s)'%(chan.id, chan.gate_hh_rates, mchan, mgates)) + print( + "== Creating channel: %s (%s) -> %s (%s)" + % (chan.id, chan.gate_hh_rates, mchan, mgates) + ) all_gates = chan.gates + chan.gate_hh_rates - # Sort all_gates such that they come in x, y, z order. - all_gates = _gates_sorted( all_gates ) - for ngate, mgate in zip(all_gates, mgates): - if ngate is None: - continue - if mgate.name.endswith('X'): - mchan.Xpower = ngate.instances - elif mgate.name.endswith('Y'): - mchan.Ypower = ngate.instances - elif mgate.name.endswith('Z'): - mchan.Zpower = ngate.instances - mgate.min = vmin - mgate.max = vmax - mgate.divs = vdivs - - # I saw only examples of GateHHRates in - # HH-channels, the meaning of forwardRate and - # reverseRate and steadyState are not clear in the - # classes GateHHRatesInf, GateHHRatesTau and in - # FateHHTauInf the meaning of timeCourse and - # steady state is not obvious. Is the last one - # refering to tau_inf and m_inf?? - fwd = ngate.forward_rate - rev = ngate.reverse_rate - self.paths_to_chan_elements['%s/%s'%(chan.id,ngate.id)] = '%s/%s'%(chan.id,mgate.name) - q10_scale = 1 - if ngate.q10_settings: - if ngate.q10_settings.type == 'q10Fixed': - q10_scale= float(ngate.q10_settings.fixed_q10) - elif ngate.q10_settings.type == 'q10ExpTemp': - q10_scale = math.pow( float(ngate.q10_settings.q10_factor) - , (self._getTemperature()- SI(ngate.q10_settings.experimental_temp))/10 - ) - else: - raise Exception('Unknown Q10 scaling type %s: %s'%( - ngate.q10_settings.type,ngate.q10_settings) - ) - - logger_.debug('+ Gate: %s; %s; %s; %s; %s; scale=%s'% ( - ngate.id, mgate.path, mchan.Xpower, fwd, rev, q10_scale) + # If user set bnml channels' id to 'x', 'y' or 'z' then pair this gate + # with moose.HHChannel's gateX, gateY, gateZ respectively. Else pair + # them with gateX, gateY, gateZ acording to list order. + for mgate, ngate in _pairNmlGateWithMooseGates(mgates, all_gates): + self._addGateToHHChannel(chan, mchan, mgate, ngate, vmin, vmax, vdivs) + logger_.debug("== Created %s for %s" % (mchan.path, chan.id)) + return mchan + + def _addGateToHHChannel(self, chan, mchan, mgate, ngate, vmin, vmax, vdivs): + """Add gateX, gateY, gateZ etc to moose.HHChannel (mchan). + + Each gate can be voltage dependant and/or concentration dependant. + Only caConc dependant channels are supported. + """ + + # set mgate.Xpower, .Ypower etc. + setattr(mchan, _whichGate(mgate) + "power", ngate.instances) + + mgate.min = vmin + mgate.max = vmax + mgate.divs = vdivs + + # Note by Padraig: + # --------------- + # I saw only examples of GateHHRates in HH-channels, the meaning of + # forwardRate and reverseRate and steadyState are not clear in the + # classes GateHHRatesInf, GateHHRatesTau and in FateHHTauInf the + # meaning of timeCourse and steady state is not obvious. Is the last + # one # refering to tau_inf and m_inf?? + fwd = ngate.forward_rate + rev = ngate.reverse_rate + + self.paths_to_chan_elements["%s/%s" % (chan.id, ngate.id)] = "%s/%s" % ( + chan.id, + mgate.name, + ) + + q10_scale = 1 + if ngate.q10_settings: + if ngate.q10_settings.type == "q10Fixed": + q10_scale = float(ngate.q10_settings.fixed_q10) + elif ngate.q10_settings.type == "q10ExpTemp": + q10_scale = math.pow( + float(ngate.q10_settings.q10_factor), + (self._getTemperature() - SI(ngate.q10_settings.experimental_temp)) + / 10, ) - - if (fwd is not None) and (rev is not None): - alpha = self.calculateRateFn(fwd, vmin, vmax, vdivs) - beta = self.calculateRateFn(rev, vmin, vmax, vdivs) - - mgate.tableA = q10_scale * (alpha) - mgate.tableB = q10_scale * (alpha + beta) - - # Assuming the meaning of the elements in GateHHTauInf ... - if hasattr(ngate,'time_course') and hasattr(ngate,'steady_state') \ - and (ngate.time_course is not None) and (ngate.steady_state is not None): - tau = ngate.time_course - inf = ngate.steady_state - tau = self.calculateRateFn(tau, vmin, vmax, vdivs) + logger_.debug( + "Q10: %s; %s; %s; %s" + % ( + ngate.q10_settings.q10_factor, + self._getTemperature(), + SI(ngate.q10_settings.experimental_temp), + q10_scale, + ) + ) + else: + raise Exception( + "Unknown Q10 scaling type %s: %s" + % (ngate.q10_settings.type, ngate.q10_settings) + ) + logger_.info( + " === Gate: %s; %s; %s; %s; %s; scale=%s" + % (ngate.id, mgate.path, mchan.Xpower, fwd, rev, q10_scale) + ) + + if (fwd is not None) and (rev is not None): + # Note: MOOSE HHGate are either voltage of concentration + # dependant. Here we figure out if nml description of gate is + # concentration dependant or not. + alpha = self.calculateRateFn(fwd, mgate, vmin, vmax, vdivs) + beta = self.calculateRateFn(rev, mgate, vmin, vmax, vdivs) + + mgate.tableA = q10_scale * (alpha) + mgate.tableB = q10_scale * (alpha + beta) + + # Assuming the meaning of the elements in GateHHTauInf ... + if ( + hasattr(ngate, "time_course") + and hasattr(ngate, "steady_state") + and (ngate.time_course is not None) + and (ngate.steady_state is not None) + ): + tau = ngate.time_course + inf = ngate.steady_state + tau = self.calculateRateFn(tau, mgate, vmin, vmax, vdivs) + inf = self.calculateRateFn(inf, mgate, vmin, vmax, vdivs) + mgate.tableA = q10_scale * (inf / tau) + mgate.tableB = q10_scale * (1 / tau) + + if ( + hasattr(ngate, "steady_state") + and (ngate.time_course is None) + and (ngate.steady_state is not None) + ): + inf = ngate.steady_state + tau = 1 / (alpha + beta) + if inf is not None: inf = self.calculateRateFn(inf, vmin, vmax, vdivs) mgate.tableA = q10_scale * (inf / tau) mgate.tableB = q10_scale * (1 / tau) - - if hasattr(ngate,'steady_state') and (ngate.time_course is None) and (ngate.steady_state is not None): - inf = ngate.steady_state - tau = 1 / (alpha + beta) - if inf is not None: - inf = self.calculateRateFn(inf, vmin, vmax, vdivs) - if len(inf) > 0: - mgate.tableA = q10_scale * (inf / tau) - mgate.tableB = q10_scale * (1 / tau) - - logger_.info('%s: Created %s for %s'%(self.filename,mchan.path,chan.id)) - return mchan def createPassiveChannel(self, chan): - epath = '%s/%s' % (self.lib.path, chan.id) - if moose.exists( epath ): - mchan = moose.element(epath) - else: - mchan = moose.Leakage(epath) - logger_.info('%s: Created %s for %s'%(self.filename,mchan.path,chan.id)) + mchan = moose.Leakage("%s/%s" % (self.lib.path, chan.id)) + if self.verbose: + print(self.filename, "Created", mchan.path, "for", chan.id) return mchan def importInputs(self, doc): - epath = '%s/inputs' % (self.lib.path) - if moose.exists( epath ): - minputs = moose.element( epath ) - else: - minputs = moose.Neutral( epath ) + minputs = moose.Neutral("%s/inputs" % (self.lib.path)) for pg_nml in doc.pulse_generators: - epath = '%s/%s' % (minputs.path, pg_nml.id) - pg = moose.element(epath) if moose.exists(epath) else moose.PulseGen(epath) + assert pg_nml.id + pg = moose.PulseGen("%s/%s" % (minputs.path, pg_nml.id)) pg.firstDelay = SI(pg_nml.delay) pg.firstWidth = SI(pg_nml.duration) pg.firstLevel = SI(pg_nml.amplitude) pg.secondDelay = 1e9 - def importIonChannels(self, doc, vmin=-150e-3, vmax=100e-3, vdivs=5000): - logger_.info('%s: Importing the ion channels' % self.filename ) - - for chan in doc.ion_channel+doc.ion_channel_hhs: - if chan.type == 'ionChannelHH': + if self.verbose: + print(self.filename, "Importing the ion channels") + + for chan in doc.ion_channel + doc.ion_channel_hhs: + if chan.type == "ionChannelHH": mchan = self.createHHChannel(chan) elif self.isPassiveChan(chan): mchan = self.createPassiveChannel(chan) else: mchan = self.createHHChannel(chan) - + + assert chan.id, "Empty id is not allowed" self.id_to_ionChannel[chan.id] = chan - self.nml_to_moose[chan.id] = mchan + self.nml_chans_to_moose[chan.id] = mchan self.proto_chans[chan.id] = mchan - logger_.info(self.filename + ': Created ion channel %s for %s %s'%( - mchan.path, chan.type, chan.id)) + if self.verbose: + print( + self.filename, + "Created ion channel", + mchan.path, + "for", + chan.type, + chan.id, + ) def importConcentrationModels(self, doc): for concModel in doc.decaying_pool_concentration_models: + # proto = self.createDecayingPoolConcentrationModel(concModel) self.createDecayingPoolConcentrationModel(concModel) def createDecayingPoolConcentrationModel(self, concModel): - """Create prototype for concentration model""" - if hasattr(concModel, 'name') and concModel.name is not None: + """Create prototype for concentration model""" + assert concModel.id, "Empty id is not allowed" + name = concModel.id + if hasattr(concModel, "name") and concModel.name is not None: name = concModel.name - else: - name = concModel.id + ca = moose.CaConc("%s/%s" % (self.lib.path, name)) - ca = moose.CaConc('%s/%s' % (self.lib.path, name)) ca.CaBasal = SI(concModel.resting_conc) ca.tau = SI(concModel.decay_constant) ca.thick = SI(concModel.shell_thickness) - ca.B = 5.2e-6 # B = 5.2e-6/(Ad) where A is the area of the - # shell and d is thickness - must divide by - # shell volume when copying + + # B = 5.2e-6/(Ad) where A is the area of the shell and d is thickness - must divide by shell volume when copying + ca.B = 5.2e-6 self.proto_pools[concModel.id] = ca - self.nml_to_moose[name] = ca + self.nml_concs_to_moose[concModel.id] = ca self.moose_to_nml[ca] = concModel - logger_.debug('Created moose element: %s for nml conc %s' % (ca.path, concModel.id)) + logger_.debug( + "Created moose element: %s for nml conc %s" % (ca.path, concModel.id) + ) diff --git a/python/moose/server.py b/python/moose/server.py index d7b1d05a8e..017448910e 100644 --- a/python/moose/server.py +++ b/python/moose/server.py @@ -379,7 +379,7 @@ def start_server( host, port, max_requests = 10 ): sock_.settimeout(10) try: conn, (ip, port) = sock_.accept() - except socket.timeout as e: + except socket.timeout: continue sock_.settimeout(0.0) t = threading.Thread(target=handle_client, args=(conn, ip, port)) diff --git a/tests/support/Makefile b/tests/support/Makefile new file mode 100644 index 0000000000..52f539e3df --- /dev/null +++ b/tests/support/Makefile @@ -0,0 +1,5 @@ +all : test_nml2moose + + +test_nml2moose : ./nml2moose.xsl + xsltproc $< ./nml_files/NML2_FullCell.nml diff --git a/tests/support/nml2moose.xsl b/tests/support/nml2moose.xsl new file mode 100644 index 0000000000..bab98efe3d --- /dev/null +++ b/tests/support/nml2moose.xsl @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + " + + + :[] + + + + + + + + + + + + + + diff --git a/tests/support/nml_files/CaPool.nml b/tests/support/nml_files/CaPool.nml new file mode 100644 index 0000000000..2358c75b5d --- /dev/null +++ b/tests/support/nml_files/CaPool.nml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/tests/support/nml_files/LEMS_hhCell.xml b/tests/support/nml_files/LEMS_hhCell.xml new file mode 100644 index 0000000000..09363c309e --- /dev/null +++ b/tests/support/nml_files/LEMS_hhCell.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/support/nml_files/LEMS_passiveCell.xml b/tests/support/nml_files/LEMS_passiveCell.xml new file mode 100644 index 0000000000..f6e48f6842 --- /dev/null +++ b/tests/support/nml_files/LEMS_passiveCell.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/support/nml_files/MScellupdated_primDend.nml b/tests/support/nml_files/MScellupdated_primDend.nml new file mode 100644 index 0000000000..26d9c80727 --- /dev/null +++ b/tests/support/nml_files/MScellupdated_primDend.nml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/support/nml_files/NML2_AbstractCells.nml b/tests/support/nml_files/NML2_AbstractCells.nml new file mode 100644 index 0000000000..ca53f04481 --- /dev/null +++ b/tests/support/nml_files/NML2_AbstractCells.nml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/support/nml_files/NML2_AnalogSynapses.nml b/tests/support/nml_files/NML2_AnalogSynapses.nml new file mode 100644 index 0000000000..6d949deae2 --- /dev/null +++ b/tests/support/nml_files/NML2_AnalogSynapses.nml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/support/nml_files/NML2_AnalogSynapsesHH.nml b/tests/support/nml_files/NML2_AnalogSynapsesHH.nml new file mode 100644 index 0000000000..75db6c4c6e --- /dev/null +++ b/tests/support/nml_files/NML2_AnalogSynapsesHH.nml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/support/nml_files/NML2_FullCell.nml b/tests/support/nml_files/NML2_FullCell.nml new file mode 100644 index 0000000000..fffc74f53b --- /dev/null +++ b/tests/support/nml_files/NML2_FullCell.nml @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + A Simple Spiking cell for testing purposes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/support/nml_files/NML2_FullNeuroML.nml b/tests/support/nml_files/NML2_FullNeuroML.nml new file mode 100644 index 0000000000..a824e3e87f --- /dev/null +++ b/tests/support/nml_files/NML2_FullNeuroML.nml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/support/nml_files/NML2_GapJunctionInstances.nml b/tests/support/nml_files/NML2_GapJunctionInstances.nml new file mode 100644 index 0000000000..79f80c1b1e --- /dev/null +++ b/tests/support/nml_files/NML2_GapJunctionInstances.nml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/support/nml_files/NML2_GapJunctions.nml b/tests/support/nml_files/NML2_GapJunctions.nml new file mode 100644 index 0000000000..7d44119021 --- /dev/null +++ b/tests/support/nml_files/NML2_GapJunctions.nml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/support/nml_files/NML2_InhomogeneousParams.nml b/tests/support/nml_files/NML2_InhomogeneousParams.nml new file mode 100644 index 0000000000..3172cd683d --- /dev/null +++ b/tests/support/nml_files/NML2_InhomogeneousParams.nml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/support/nml_files/NML2_Inputs.nml b/tests/support/nml_files/NML2_Inputs.nml new file mode 100644 index 0000000000..e466ad9a7c --- /dev/null +++ b/tests/support/nml_files/NML2_Inputs.nml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/support/nml_files/NML2_InstanceBasedNetwork.nml b/tests/support/nml_files/NML2_InstanceBasedNetwork.nml new file mode 100644 index 0000000000..d8a2e0624b --- /dev/null +++ b/tests/support/nml_files/NML2_InstanceBasedNetwork.nml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/support/nml_files/NML2_MultiCompCellNetwork.nml b/tests/support/nml_files/NML2_MultiCompCellNetwork.nml new file mode 100644 index 0000000000..063658cde3 --- /dev/null +++ b/tests/support/nml_files/NML2_MultiCompCellNetwork.nml @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + Multicompartmental cell + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/support/nml_files/NML2_SegmentConnections.nml b/tests/support/nml_files/NML2_SegmentConnections.nml new file mode 100644 index 0000000000..ebf2136762 --- /dev/null +++ b/tests/support/nml_files/NML2_SegmentConnections.nml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/support/nml_files/NML2_SimpleIonChannel.nml b/tests/support/nml_files/NML2_SimpleIonChannel.nml new file mode 100644 index 0000000000..83864f42ed --- /dev/null +++ b/tests/support/nml_files/NML2_SimpleIonChannel.nml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/support/nml_files/NML2_SimpleMorphology.nml b/tests/support/nml_files/NML2_SimpleMorphology.nml new file mode 100644 index 0000000000..2f06956a6a --- /dev/null +++ b/tests/support/nml_files/NML2_SimpleMorphology.nml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/support/nml_files/NML2_SingleCompHHCell.nml b/tests/support/nml_files/NML2_SingleCompHHCell.nml new file mode 100644 index 0000000000..1b1d43b926 --- /dev/null +++ b/tests/support/nml_files/NML2_SingleCompHHCell.nml @@ -0,0 +1,90 @@ + + + + + + + + + + Leak conductance + + + + + Na channel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/support/nml_files/NML2_SynapseTypes.nml b/tests/support/nml_files/NML2_SynapseTypes.nml new file mode 100644 index 0000000000..b2084b00e4 --- /dev/null +++ b/tests/support/nml_files/NML2_SynapseTypes.nml @@ -0,0 +1,80 @@ + + + + + + + + An alpha synapse with time for rise equal to decay. + + + + + A simple monoexponential synapse. + + + + + A biexponential synapse. + + + + + A synapse consisting of one rise and two decay time courses. + + + + + A biexponential synapse exhibiting STD. + + + + + + A biexponential synapse with short term depression + and facilitation. + + + + + + A biexponential blocking synapse, with STD. + + + + + + + A biexponential blocking synapse with short term + depression and facilitation. + + + + + + + + + + A single "synapse" which contains both AMPA and NMDA. It is planned that the need for extra synapse1Path/synapse2Path attributes can be removed in later versions. + + + diff --git a/tests/support/nml_files/Purk2M9s.nml b/tests/support/nml_files/Purk2M9s.nml new file mode 100644 index 0000000000..511ab43e06 --- /dev/null +++ b/tests/support/nml_files/Purk2M9s.nml @@ -0,0 +1,20834 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/support/nml_files/README b/tests/support/nml_files/README new file mode 100644 index 0000000000..4bb616d5f2 --- /dev/null +++ b/tests/support/nml_files/README @@ -0,0 +1 @@ +Files starting with NML2_ in this folder will be valid against ../Schemas/NeuroML2/NeuroML_v2beta.xsd diff --git a/tests/support/nml_files/SKchannel2.nml b/tests/support/nml_files/SKchannel2.nml new file mode 100644 index 0000000000..9c2605d67a --- /dev/null +++ b/tests/support/nml_files/SKchannel2.nml @@ -0,0 +1,107 @@ + + + + + + + Small-conductance, Ca2+ activated K+ current + +Comment from original mod file: +: SK-type calcium-activated potassium current +: Reference : Kohler et al. 1996 + + + + + + + + Models of Neocortical Layer 5b Pyramidal Cells Capturing a Wide Range of Dendritic and Perisomatic Active Properties, + Etay Hay, Sean Hill, Felix Schürmann, Henry Markram and Idan Segev, PLoS Comp Biol 2011 + + + + + + + + K channels + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/support/nml_files/SimpleIonChannel.xml b/tests/support/nml_files/SimpleIonChannel.xml new file mode 100644 index 0000000000..02188151df --- /dev/null +++ b/tests/support/nml_files/SimpleIonChannel.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/support/nml_files/pas.channel.nml b/tests/support/nml_files/pas.channel.nml new file mode 100644 index 0000000000..16ed312a3e --- /dev/null +++ b/tests/support/nml_files/pas.channel.nml @@ -0,0 +1,12 @@ + + + + NeuroML file containing a single Channel description + + + + Simple example of a leak/passive conductance. + + + + diff --git a/tests/support/nml_files/passiveCell.nml b/tests/support/nml_files/passiveCell.nml new file mode 100644 index 0000000000..9b91f2530d --- /dev/null +++ b/tests/support/nml_files/passiveCell.nml @@ -0,0 +1,52 @@ + + + + + + + Leak conductance + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/support/test_files b/tests/support/test_files deleted file mode 120000 index 6866342fef..0000000000 --- a/tests/support/test_files +++ /dev/null @@ -1 +0,0 @@ -../../python/moose/neuroml2/test_files \ No newline at end of file diff --git a/tests/support/test_neuroml2.py b/tests/support/test_neuroml2.py deleted file mode 100644 index 06275d6226..0000000000 --- a/tests/support/test_neuroml2.py +++ /dev/null @@ -1,56 +0,0 @@ -# -*- coding: utf-8 -*- -# test_neurom2.py, modified from run_cell.py -# Maintainer: P Gleeson, Dilawar Singh -# This test is not robust. -# Code: - -from __future__ import absolute_import, print_function, division - -# check if neuroml working properly. -# NOTE: This script does not work with python3 -# See https://github.com/NeuroML/NeuroML2/issues/116 . If this bug is fixed then -# remove this code block. - -import moose -import moose.utils as mu -import os -import numpy as np - -SCRIPT_DIR = os.path.dirname( os.path.realpath( __file__ ) ) - - -def test_nml2( nogui = True ): - global SCRIPT_DIR - filename = os.path.join(SCRIPT_DIR, 'test_files/passiveCell.nml' ) - mu.info('Loading: %s' % filename ) - nml = moose.mooseReadNML2( filename ) - if not nml: - mu.warn( "Failed to parse NML2 file" ) - return - - assert nml, "Expecting NML2 object" - msoma = nml.getComp(nml.doc.networks[0].populations[0].id,0,0) - data = moose.Neutral('/data') - pg = nml.getInput('pulseGen1') - - inj = moose.Table('%s/pulse' % (data.path)) - moose.connect(inj, 'requestOut', pg, 'getOutputValue') - - vm = moose.Table('%s/Vm' % (data.path)) - moose.connect(vm, 'requestOut', msoma, 'getVm') - - simtime = 150e-3 - moose.reinit() - moose.start(simtime) - print("Finished simulation!") - yvec = vm.vector - injvec = inj.vector * 1e12 - m1, u1 = np.mean( yvec ), np.std( yvec ) - m2, u2 = np.mean( injvec ), np.std( injvec ) - assert np.isclose( m1, -0.0456943 ), m1 - assert np.isclose( u1, 0.0121968 ), u1 - assert np.isclose( m2, 26.64890 ), m2 - assert np.isclose( u2, 37.70607574 ), u2 - -if __name__ == '__main__': - test_nml2() diff --git a/tests/support/test_nml2.py b/tests/support/test_nml2.py new file mode 100644 index 0000000000..d9b77df029 --- /dev/null +++ b/tests/support/test_nml2.py @@ -0,0 +1,224 @@ +# Author: @jkopsick (github) https://github.com/jkopsick +# +# Turned into a test case by Dilawar Singh + +import os +import matplotlib +matplotlib.use('Agg') +import matplotlib.pyplot as plt + +import moose +import moose.utils as mu + +print("[INFO ] Using moose from %s" % moose.__file__) +import numpy as np +import datetime + +SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) + + +def plot_gate_params(chan, plotpow, VMIN=-0.1, VMAX=0.05, CAMIN=0, CAMAX=1): + """Plot the gate parameters like m and h of the channel.""" + if chan.className == 'HHChannel': + print("[INFO ] Testing moose.HHChannel with CaConc") + cols = 1 + #n=range(0,2,1) + if chan.Zpower != 0 and (chan.Xpower != 0 or chan.Ypower != 0 + ) and chan.useConcentration == True: + fig, axes = plt.subplots(3, cols, sharex=False) + axes[1].set_xlabel('voltage') + axes[2].set_xlabel('Calcium') + else: + fig, axes = plt.subplots(2, cols, sharex=True) + axes[1].set_xlabel('voltage') + plt.suptitle(chan.name) + + if chan.Xpower > 0: + assert False, "Should load into gateZ" + gate = moose.element(chan.path + '/gateX') + ma = gate.tableA + mb = gate.tableB + varray = np.linspace(gate.min, gate.max, len(ma)) + axes[0].plot(varray, 1e3 / mb, label='Xtau ' + chan.name) + labelpow = '(Xinf)**{}'.format(chan.Xpower) + infpow = (ma / mb)**chan.Xpower + label = 'Xinf' + inf = ma / mb + axes[1].plot(varray, inf, label=label) + axes[1].plot(varray, infpow, label=labelpow) + axes[1].axis([gate.min, gate.max, 0, 1]) + + if chan.Ypower > 0: + assert False, "Should load into gateZ" + gate = moose.element(chan.path + '/gateY') + ha = gate.tableA + hb = gate.tableB + varray = np.linspace(gate.min, gate.max, len(ha)) + axes[0].plot(varray, 1e3 / hb, label='Ytau ' + chan.name) + axes[1].plot(varray, ha / hb, label='Yinf ' + chan.name) + axes[1].axis([gate.min, gate.max, 0, 1]) + + if chan.Zpower != 0: + gate = moose.element(chan.path + '/gateZ') + gate.min = CAMIN + gate.max = CAMAX + za = gate.tableA + zb = gate.tableB + Z = za / zb + + # FIXME: These values may not be correct. Once verified, remove + # this comment or fix the test. + assert np.isclose(Z.mean(), 0.9954291788156363) + assert np.isclose(Z.std(), 0.06818901739648629) + + xarray = np.linspace(gate.min, gate.max, len(za)) + if (chan.Xpower == 0 + and chan.Ypower == 0) or chan.useConcentration == False: + axes[0].plot(xarray, 1e3 / zb, label='ztau ' + chan.name) + axes[1].plot(xarray, za / zb, label='zinf' + chan.name) + if chan.useConcentration == True: + axes[1].set_xlabel('Calcium') + else: + axes[2].set_xscale("log") + axes[2].set_ylabel('ss, tau (s)') + axes[2].plot(xarray, 1 / zb, label='ztau ' + chan.name) + axes[2].plot(xarray, za / zb, label='zinf ' + chan.name) + axes[2].legend(loc='best', fontsize=8) + axes[0].set_ylabel('tau, ms') + axes[1].set_ylabel('steady state') + axes[0].legend(loc='best', fontsize=8) + axes[1].legend(loc='best', fontsize=8) + else: #Must be two-D tab channel + plt.figure() + + ma = moose.element(chan.path + '/gateX').tableA + mb = moose.element(chan.path + '/gateX').tableB + ma = np.array(ma) + mb = np.array(mb) + + plt.subplot(211) + + plt.title(chan.name + '/gateX top: tau (ms), bottom: ss') + plt.imshow(1e3 / mb, + extent=[CAMIN, CAMAX, VMIN, VMAX], + aspect='auto', + origin='lower') + plt.colorbar() + + plt.subplot(212) + if plotpow: + inf = (ma / mb)**chan.Xpower + else: + inf = ma / mb + + plt.imshow(inf, + extent=[CAMIN, CAMAX, VMIN, VMAX], + aspect='auto', + origin='lower') + plt.xlabel('Ca [mM]') + plt.ylabel('Vm [V]') + plt.colorbar() + if chan.Ypower > 0: + ha = moose.element(chan.path + '/gateY').tableA + hb = moose.element(chan.path + '/gateY').tableB + ha = np.array(ha) + hb = np.array(hb) + + plt.figure() + plt.subplot(211) + plt.suptitle(chan.name + '/gateY tau') + plt.imshow(1e3 / hb, + extent=[CAMIN, CAMAX, VMIN, VMAX], + aspect='auto') + + plt.colorbar() + plt.subplot(212) + if plotpow: + inf = (ha / hb)**chan.Ypower + else: + inf = ha / hb + plt.imshow(inf, extent=[CAMIN, CAMAX, VMIN, VMAX], aspect='auto') + plt.xlabel('Ca [nM]') + plt.ylabel('Vm [V]') + plt.colorbar() + return + + +def test_nml2(nogui=True): + global SCRIPT_DIR + filename = os.path.join(SCRIPT_DIR, 'nml_files/passiveCell.nml') + mu.info('Loading: %s' % filename) + nml = moose.mooseReadNML2(filename) + if not nml: + mu.warn("Failed to parse NML2 file") + return + + assert nml, "Expecting NML2 object" + msoma = nml.getComp(nml.doc.networks[0].populations[0].id, 0, 0) + data = moose.Neutral('/data') + pg = nml.getInput('pulseGen1') + + inj = moose.Table('%s/pulse' % (data.path)) + moose.connect(inj, 'requestOut', pg, 'getOutputValue') + + vm = moose.Table('%s/Vm' % (data.path)) + moose.connect(vm, 'requestOut', msoma, 'getVm') + + simtime = 150e-3 + moose.reinit() + moose.start(simtime) + print("Finished simulation!") + yvec = vm.vector + injvec = inj.vector * 1e12 + m1, u1 = np.mean(yvec), np.std(yvec) + m2, u2 = np.mean(injvec), np.std(injvec) + assert np.isclose(m1, -0.0456943), m1 + assert np.isclose(u1, 0.0121968), u1 + assert np.isclose(m2, 26.64890), m2 + assert np.isclose(u2, 37.70607574), u2 + + +def test_nml2_jkopsick(): + # Read the NML model into MOOSE + filename = os.path.join(SCRIPT_DIR, 'nml_files/MScellupdated_primDend.nml') + moose.mooseReadNML2(filename, verbose=1) + + # Define the variables needed to view the underlying curves for the channel kinetics + plot_powers = True + VMIN = -120e-3 + VMAX = 50e-3 + CAMIN = 0.01e-3 + CAMAX = 40e-3 + + # Graph the channel kinetics for the SKCa channel -- the plot doesn't + # currently show up due to the error + # in copying the CaPool mechanism, but works if you run it manually after + # the code completes. + libchan = moose.element('/library' + '/' + 'SKCa') + plot_gate_params(libchan, plot_powers, VMIN, VMAX, CAMIN, CAMAX) + + stamp = datetime.datetime.now().isoformat() + plt.suptitle(stamp, fontsize=6) + plt.tight_layout() + plt.savefig(__file__ + ".png") + +def test_parse_nml_files(): + import glob + files = glob.glob(os.path.join(SCRIPT_DIR, 'nml_files', 'NML2_*.nml')) + print("Total %s files found" % len(files)) + for f in files: + if moose.exists('/model'): moose.delete('/model') + if moose.exists('/library'): moose.delete('/library') + print("=========================================") + print("[INFO ] Reading file %s" % f) + moose.mooseReadNML2(f) + + +def main(): + test_parse_nml_files() + test_nml2() + test_nml2_jkopsick() + + +if __name__ == '__main__': + main()