From 24dea42663c8081485cbd88195e1d67ccfd957d0 Mon Sep 17 00:00:00 2001 From: HarshaRani <ranishashi@gmail.com> Date: Fri, 14 Apr 2017 16:00:29 +0530 Subject: [PATCH] Squashed 'moose-core/' changes from 434c478..c15c1b1 c15c1b1 Changes to testSynapse so it can compile in DEBUG mode. Issue #175. e4caa2f Merge branch 'master' of github.com:BhallaLab/moose-core f99cd77 Removed VERSION file .. again. 7646e6b Python3/python2 compatible import statements. b77448d Removed VERSION file from source. 97e1a25 Fixed broken test in synapse/testSynapse.cpp file eb4eeb2 Install python3-numpy using pip on travis. Another failure is with synapse tests setResponseScale and setWeightScale ; these functions are not available. 1998b5f Fixes to python3 import . 22849ab Find python3 on travis. f5870c9 missing parentheses for print stm 17462d1 Merge branch 'master' of https://github.com/BhallaLab/moose-core 9471341 Group's with annotation is written and read from SBML model 5ab33ad Put SparseMatrix access functions into SparseMsg 46d80cc All default units are added, as some of the simulator requires all the units to be specfied, km unit is defined, group and annotation to the group (compartment and color) is added b76929f Find gsl header as well. 4df3c47 If user set the GSL_ROOT_DIR then do not search in system dir. 1ef020e Always use private muparser. abfa2c8 Merge branch 'master' of https://github.com/BhallaLab/moose-core ff7bf04 Moved isBuffered field from Pool to PoolBase. c470f10 group information is populated as per SBML rules under listofGroups instead of annotation 70c1e8b clean up in documention 98c5a76 Hopefully description given for merging the files will be clear to user git-subtree-dir: moose-core git-subtree-split: c15c1b1b41e429e96ea769c85c105e6167c68ffa --- .travis/travis_build_linux.sh | 2 +- .travis/travis_prepare_linux.sh | 1 + CMakeLists.txt | 12 +- VERSION | 1 - basecode/SparseMatrix.h | 13 + cmake_modules/FindGSL.cmake | 42 +-- kinetics/BufPool.cpp | 1 - kinetics/Pool.cpp | 28 +- kinetics/Pool.h | 4 +- kinetics/PoolBase.cpp | 30 ++ kinetics/PoolBase.h | 8 + ksolve/KinSparseMatrix.cpp | 15 - ksolve/KinSparseMatrix.h | 4 - ksolve/ZombieBufPool.cpp | 4 + ksolve/ZombieBufPool.h | 1 + ksolve/ZombiePool.cpp | 5 + ksolve/ZombiePool.h | 1 + msg/SparseMsg.cpp | 41 +++ msg/SparseMsg.h | 8 +- python/moose/SBML/readSBML.py | 80 +++-- python/moose/SBML/writeSBML.py | 217 +++++++++++--- python/moose/__init__.py | 514 ++++++++++++++++++++++++++++++-- python/moose/merge/merge.py | 77 +++-- python/moose/moose.py | 508 ------------------------------- python/rdesigneur/rdesigneur.py | 5 +- python/rdesigneur/rmoogli.py | 4 +- synapse/testSynapse.cpp | 10 +- 27 files changed, 945 insertions(+), 691 deletions(-) delete mode 100644 VERSION delete mode 100644 python/moose/moose.py diff --git a/.travis/travis_build_linux.sh b/.travis/travis_build_linux.sh index b993e109..5530f9a7 100755 --- a/.travis/travis_build_linux.sh +++ b/.travis/travis_build_linux.sh @@ -21,7 +21,7 @@ set -o nounset # Treat unset variables as an error set -e PYTHON2="/usr/bin/python2" -PYTHON3="/usr/bin/python3" +PYTHON3=`which python3` #MAKEFLAGS="-j 4" # Bug: `which python` returns /opt/bin/python* etc on travis. For which numpy diff --git a/.travis/travis_prepare_linux.sh b/.travis/travis_prepare_linux.sh index ce068f9b..d016aa5b 100755 --- a/.travis/travis_prepare_linux.sh +++ b/.travis/travis_prepare_linux.sh @@ -29,3 +29,4 @@ apt-get install -qq libboost-all-dev apt-get install -qq libgsl0-dev apt-get install -qq python-pip python3-pip apt-get install -qq libgraphviz-dev +pip3 install numpy diff --git a/CMakeLists.txt b/CMakeLists.txt index aa1c243d..390904c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -305,15 +305,9 @@ if(WITH_MPI) endif() endif(WITH_MPI) -pkg_check_modules(MUPARSER muparser) -if(MUPARSER_FOUND) - message(STATUS "Using system muparser ${MUPARSER_VERSION}") - list(APPEND SYSTEM_SHARED_LIBS ${MUPARSER_LIBRARIES}) -else() - message(STATUS "Using private muparser") - add_subdirectory(external/muparser) - list(APPEND MOOSE_LIBRARIES muparser) -endif() +# Always use private version of muparser. We have some custom edits. +add_subdirectory(external/muparser) +list(APPEND MOOSE_LIBRARIES muparser) # Add subdirectroeis add_subdirectory(basecode) diff --git a/VERSION b/VERSION deleted file mode 100644 index 5b9fc17b..00000000 --- a/VERSION +++ /dev/null @@ -1 +0,0 @@ -3.1.1-100-g51a3a30 \ No newline at end of file diff --git a/basecode/SparseMatrix.h b/basecode/SparseMatrix.h index 88d2681c..059bb793 100644 --- a/basecode/SparseMatrix.h +++ b/basecode/SparseMatrix.h @@ -423,6 +423,19 @@ public: colIndexArg.begin(), colIndexArg.end() ); rowStart_[rowNum + 1] = N_.size(); } + /// Here we expose the sparse matrix for MOOSE use. + const vector< T >& matrixEntry() const + { + return N_; + } + const vector< unsigned int >& colIndex() const + { + return colIndex_; + } + const vector< unsigned int >& rowStart() const + { + return rowStart_; + } ////////////////////////////////////////////////////////////////// // Operations on entire matrix. ////////////////////////////////////////////////////////////////// diff --git a/cmake_modules/FindGSL.cmake b/cmake_modules/FindGSL.cmake index 93c2686f..99ad9ea8 100644 --- a/cmake_modules/FindGSL.cmake +++ b/cmake_modules/FindGSL.cmake @@ -63,28 +63,34 @@ ELSE(WIN32) SET(GSL_CBLAS_LIB_NAMES gslcblas) ENDIF( ) - FIND_LIBRARY(GSL_LIB - NAMES ${GSL_LIB_NAMES} - PATHS - ${GSL_ROOT_DIR}/lib ${GSL_ROOT_DIR}/lib64 - /opt/lib /opt/lib64 - ) + if(GSL_ROOT_DIR) + message(" Debug: Searching in user given path " ) + FIND_LIBRARY(GSL_LIB + NAMES ${GSL_LIB_NAMES} + PATHS ${GSL_ROOT_DIR}/lib ${GSL_ROOT_DIR}/lib64 + NO_DEFAULT_PATH + ) + + FIND_LIBRARY(GSLCBLAS_LIB + NAMES ${GSL_CBLAS_LIB_NAMES} + PATHS ${GSL_ROOT_DIR}/lib ${GSL_ROOT_DIR}/lib64 + NO_DEFAULT_PATH + ) + + FIND_PATH(GSL_INCLUDE_DIRS NAMES gsl/gsl_blas.h + PATHS ${GSL_ROOT_DIR}/include + NO_DEFAULT_PATH + ) + else( ) + FIND_LIBRARY(GSL_LIB NAMES ${GSL_LIB_NAMES} ) + FIND_LIBRARY(GSLCBLAS_LIB NAMES ${GSL_CBLAS_LIB_NAMES}) + FIND_PATH(GSL_INCLUDE_DIRS NAMES gsl/gsl_blas.h ) + endif() - FIND_LIBRARY(GSLCBLAS_LIB - NAMES ${GSL_CBLAS_LIB_NAMES} - PATHS - ${GSL_ROOT_DIR}/lib ${GSL_ROOT_DIR}/lib64 - /opt/lib /opt/lib64 - ) IF (GSL_LIB AND GSLCBLAS_LIB) SET (GSL_LIBRARIES ${GSL_LIB} ${GSLCBLAS_LIB}) ENDIF (GSL_LIB AND GSLCBLAS_LIB) - FIND_PATH(GSL_INCLUDE_DIRS NAMES gsl/gsl_blas.h - PATHS ${GSL_ROOT_DIR}/include /opt/include - ) - - ENDIF(WIN32) # FIND version @@ -100,7 +106,7 @@ endif(GSL_INCLUDE_DIRS) IF(GSL_LIBRARIES AND GSL_VERSION) IF(GSL_INCLUDE_DIRS) - MESSAGE(STATUS "Found GSL ${GSL_LIBRARIES}") + MESSAGE(STATUS "Found GSL: ${GSL_INCLUDE_DIRS}, ${GSL_LIBRARIES}") SET(GSL_FOUND 1) ENDIF(GSL_INCLUDE_DIRS) ENDIF() diff --git a/kinetics/BufPool.cpp b/kinetics/BufPool.cpp index 78c45017..54e18378 100644 --- a/kinetics/BufPool.cpp +++ b/kinetics/BufPool.cpp @@ -78,7 +78,6 @@ void BufPool::vSetConcInit( const Eref& e, double conc ) vSetConc( e, conc ); } - ////////////////////////////////////////////////////////////// // MsgDest Definitions ////////////////////////////////////////////////////////////// diff --git a/kinetics/Pool.cpp b/kinetics/Pool.cpp index 7ebc22f9..f39b1af8 100644 --- a/kinetics/Pool.cpp +++ b/kinetics/Pool.cpp @@ -20,17 +20,6 @@ const Cinfo* Pool::initCinfo() ////////////////////////////////////////////////////////////// // Field Definitions: All inherited from PoolBase. ////////////////////////////////////////////////////////////// - static ElementValueFinfo< Pool, bool > isBuffered( - "isBuffered", - "Flag: True if Pool is buffered. This field changes the " - "type of the Pool object to BufPool, or vice versa. " - "None of the messages are affected. " - "This object class flip can only be done in the non-zombified " - "form of the Pool.", - &Pool::setIsBuffered, - &Pool::getIsBuffered - ); - ////////////////////////////////////////////////////////////// // MsgDest Definitions: All inherited ////////////////////////////////////////////////////////////// @@ -40,16 +29,12 @@ const Cinfo* Pool::initCinfo() ////////////////////////////////////////////////////////////// // SharedMsg Definitions: All inherited. ////////////////////////////////////////////////////////////// - static Finfo* poolFinfos[] = { - &isBuffered, // ElementValueFinfo - }; - static Dinfo< Pool > dinfo; static Cinfo poolCinfo ( "Pool", PoolBase::initCinfo(), - poolFinfos, - sizeof( poolFinfos ) / sizeof ( Finfo* ), + 0, + 0, &dinfo ); @@ -80,10 +65,10 @@ Pool::~Pool() * It uses a low-level replaceCinfo call to just change the * identity of the Cinfo used, leaving everything else as is. */ -void Pool::setIsBuffered( const Eref& e, bool v ) +void Pool::vSetIsBuffered( const Eref& e, bool v ) { static const Cinfo* bufPoolCinfo = Cinfo::find( "BufPool" ); - if (getIsBuffered( e ) == v) + if (vGetIsBuffered( e ) == v) return; if (v) { e.element()->replaceCinfo( bufPoolCinfo ); @@ -92,8 +77,11 @@ void Pool::setIsBuffered( const Eref& e, bool v ) } } -bool Pool::getIsBuffered( const Eref& e ) const +bool Pool::vGetIsBuffered( const Eref& e ) const { + /// We need this explicit check because when the moose class is + /// flipped, the internal C++ class isn't. + /// Inherited by BufPool. return e.element()->cinfo()->name() == "BufPool"; } diff --git a/kinetics/Pool.h b/kinetics/Pool.h index 9d0cca01..4a6b2d3c 100644 --- a/kinetics/Pool.h +++ b/kinetics/Pool.h @@ -57,8 +57,8 @@ class Pool: public PoolBase /** * Functions to examine and change class between Pool and BufPool. */ - void setIsBuffered( const Eref& e, bool v ); - bool getIsBuffered( const Eref& e ) const; + void vSetIsBuffered( const Eref& e, bool v ); + bool vGetIsBuffered( const Eref& e) const; ////////////////////////////////////////////////////////////////// // Dest funcs. These too override virtual funcs in the Pool base diff --git a/kinetics/PoolBase.cpp b/kinetics/PoolBase.cpp index 59c66ba5..0324c05e 100644 --- a/kinetics/PoolBase.cpp +++ b/kinetics/PoolBase.cpp @@ -84,6 +84,18 @@ const Cinfo* PoolBase::initCinfo() &PoolBase::getSpecies ); + static ElementValueFinfo< PoolBase, bool > isBuffered( + "isBuffered", + "Flag: True if Pool is buffered. " + "In the case of Pool and BufPool the field can be assigned, to " + "change the type of the Pool object to BufPool, or vice versa. " + "None of the messages are affected. " + "This object class flip can only be done in the non-zombified " + "form of the Pool/BufPool. In Zombies it is read-only.", + &PoolBase::setIsBuffered, + &PoolBase::getIsBuffered + ); + ////////////////////////////////////////////////////////////// // MsgDest Definitions ////////////////////////////////////////////////////////////// @@ -173,6 +185,7 @@ const Cinfo* PoolBase::initCinfo() &concInit, // Value &volume, // Readonly Value &speciesId, // Value + &isBuffered, // Value &increment, // DestFinfo &decrement, // DestFinfo &nIn, // DestFinfo @@ -373,6 +386,19 @@ unsigned int PoolBase::getSpecies( const Eref& e ) const return vGetSpecies( e ); } +/** + * setIsBuffered is active only for Pool and BufPool. Otherwise ignored. + */ +void PoolBase::setIsBuffered( const Eref& e, bool v ) +{ + vSetIsBuffered( e, v ); +} + +bool PoolBase::getIsBuffered( const Eref& e ) const +{ + return vGetIsBuffered( e ); +} + ////////////////////////////////////////////////////////////// // Virtual Field Definitions ////////////////////////////////////////////////////////////// @@ -386,6 +412,10 @@ double PoolBase::vGetMotorConst(const Eref& e ) const return 0.0; } +/// Dummy default function for most pool subclasses. +void PoolBase::vSetIsBuffered( const Eref& e, bool v ) +{;} + ////////////////////////////////////////////////////////////// // Zombie conversion routine: Converts Pool subclasses. There // will typically be a target specific follow-up function, for example, diff --git a/kinetics/PoolBase.h b/kinetics/PoolBase.h index 8173c445..1bdf0a78 100644 --- a/kinetics/PoolBase.h +++ b/kinetics/PoolBase.h @@ -68,6 +68,11 @@ class PoolBase void setSpecies( const Eref& e, SpeciesId v ); SpeciesId getSpecies( const Eref& e ) const; + /** + * Functions to examine and change class between Pool and BufPool. + */ + void setIsBuffered( const Eref& e, bool v ); + bool getIsBuffered( const Eref& e ) const; ////////////////////////////////////////////////////////////////// // Here are the inner virtual funcs for fields. @@ -91,6 +96,9 @@ class PoolBase virtual void vSetVolume( const Eref& e, double v ) = 0; virtual void vSetSpecies( const Eref& e, SpeciesId v ) = 0; virtual SpeciesId vGetSpecies( const Eref& e ) const = 0; + /// I put in a default empty function for vSetIsBuffered. + virtual void vSetIsBuffered( const Eref& e, bool v ); + virtual bool vGetIsBuffered( const Eref& e) const = 0; /** * Assign whatever info is needed by the zombie based on the * solver Element. Encapsulates some unpleasant field extraction, diff --git a/ksolve/KinSparseMatrix.cpp b/ksolve/KinSparseMatrix.cpp index a83e12ae..431fb858 100644 --- a/ksolve/KinSparseMatrix.cpp +++ b/ksolve/KinSparseMatrix.cpp @@ -164,21 +164,6 @@ void makeVecUnique( vector< unsigned int >& v ) v.resize( pos - v.begin() ); } -vector< int > KinSparseMatrix::matrixEntry() const -{ - return N_; -} - -vector< unsigned int > KinSparseMatrix::colIndex() const -{ - return colIndex_; -} - -vector< unsigned int > KinSparseMatrix::rowStart() const -{ - return rowStart_; -} - #ifdef DO_UNIT_TESTS #include "header.h" diff --git a/ksolve/KinSparseMatrix.h b/ksolve/KinSparseMatrix.h index 9d18c262..3d316738 100644 --- a/ksolve/KinSparseMatrix.h +++ b/ksolve/KinSparseMatrix.h @@ -61,10 +61,6 @@ class KinSparseMatrix: public SparseMatrix< int > */ void truncateRow( unsigned int maxColumnIndex ); - /// Here we expose the sparse matrix for MOOSE use. - vector< int > matrixEntry() const; - vector< unsigned int > colIndex() const; - vector< unsigned int > rowStart() const; private: /** * End colIndex for rows (molecules in the transposed matrix) diff --git a/ksolve/ZombieBufPool.cpp b/ksolve/ZombieBufPool.cpp index a00a6499..82665529 100644 --- a/ksolve/ZombieBufPool.cpp +++ b/ksolve/ZombieBufPool.cpp @@ -72,3 +72,7 @@ void ZombieBufPool::vSetConcInit( const Eref& e, double conc ) vSetConc( e, conc ); } +bool ZombieBufPool::vGetIsBuffered( const Eref& e ) const +{ + return true; +} diff --git a/ksolve/ZombieBufPool.h b/ksolve/ZombieBufPool.h index 72d0a200..6ebdf8bc 100644 --- a/ksolve/ZombieBufPool.h +++ b/ksolve/ZombieBufPool.h @@ -21,6 +21,7 @@ class ZombieBufPool: public ZombiePool void vSetNinit( const Eref& e, double v ); void vSetConc( const Eref& e, double v ); void vSetConcInit( const Eref& e, double v ); + bool vGetIsBuffered( const Eref& e ) const; static const Cinfo* initCinfo(); private: diff --git a/ksolve/ZombiePool.cpp b/ksolve/ZombiePool.cpp index af4a2632..4ab7e1f8 100644 --- a/ksolve/ZombiePool.cpp +++ b/ksolve/ZombiePool.cpp @@ -179,6 +179,11 @@ double ZombiePool::vGetVolume( const Eref& e ) const return lookupVolumeFromMesh( e ); } +bool ZombiePool::vGetIsBuffered( const Eref& e ) const +{ + return false; +} + ////////////////////////////////////////////////////////////// // Zombie conversion functions. ////////////////////////////////////////////////////////////// diff --git a/ksolve/ZombiePool.h b/ksolve/ZombiePool.h index 6771b2ce..8e9b6ddb 100644 --- a/ksolve/ZombiePool.h +++ b/ksolve/ZombiePool.h @@ -46,6 +46,7 @@ class ZombiePool: public PoolBase void vSetMotorConst( const Eref& e, double v ); double vGetMotorConst( const Eref& e ) const; + bool vGetIsBuffered( const Eref& e ) const; ////////////////////////////////////////////////////////////////// // Dest funcs ////////////////////////////////////////////////////////////////// diff --git a/msg/SparseMsg.cpp b/msg/SparseMsg.cpp index 44f79d13..12d9da4d 100644 --- a/msg/SparseMsg.cpp +++ b/msg/SparseMsg.cpp @@ -41,6 +41,29 @@ const Cinfo* SparseMsg::initCinfo() "Number of Entries in matrix.", &SparseMsg::getNumEntries ); + /// Connection matrix entries to manipulate in Python. + static ReadOnlyValueFinfo< SparseMsg, vector< unsigned int > > + matrixEntry( + "matrixEntry", + "The non-zero matrix entries in the sparse matrix. Their" + "column indices are in a separate vector and the row" + "informatino in a third", + &SparseMsg::getMatrixEntry + ); + /// connection matrix column indices to manipulate in Python. + static ReadOnlyValueFinfo< SparseMsg, vector< unsigned int > > + columnIndex( + "columnIndex", + "Column Index of each matrix entry", + &SparseMsg::getColIndex + ); + /// connection matrix rowStart to manipulate in Python. + static ReadOnlyValueFinfo< SparseMsg, vector< unsigned int > > + rowStart( + "rowStart", + "Row start for each block of entries and column indices", + &SparseMsg::getRowStart + ); static ValueFinfo< SparseMsg, double > probability( "probability", @@ -109,6 +132,9 @@ const Cinfo* SparseMsg::initCinfo() &numRows, // readonly value &numColumns, // readonly value &numEntries, // readonly value + &matrixEntry, // ReadOnlyValue + &columnIndex, // ReadOnlyValue + &rowStart, // ReadOnlyValue &probability, // value &seed, // value &setRandomConnectivity, // dest @@ -176,6 +202,21 @@ unsigned int SparseMsg::getNumEntries() const return matrix_.nEntries(); } +vector< unsigned int > SparseMsg::getMatrixEntry() const +{ + return matrix_.matrixEntry(); +} + +vector< unsigned int > SparseMsg::getColIndex() const +{ + return matrix_.colIndex(); +} + +vector< unsigned int > SparseMsg::getRowStart() const +{ + return matrix_.rowStart(); +} + ////////////////////////////////////////////////////////////////// // DestFields ////////////////////////////////////////////////////////////////// diff --git a/msg/SparseMsg.h b/msg/SparseMsg.h index 2dffb9af..ac300cfc 100644 --- a/msg/SparseMsg.h +++ b/msg/SparseMsg.h @@ -87,11 +87,15 @@ class SparseMsg: public Msg void unsetEntry( unsigned int row, unsigned int column ); - // Still need to implement array field gets. - unsigned int getNumRows() const; unsigned int getNumColumns() const; unsigned int getNumEntries() const; + /// Return array entries in sparse matrix form + vector< unsigned int > getMatrixEntry() const; + /// Return column index for each array entry + vector< unsigned int > getColIndex() const; + /// row start number for each array entry + vector< unsigned int > getRowStart() const; void clear(); void transpose(); diff --git a/python/moose/SBML/readSBML.py b/python/moose/SBML/readSBML.py index 6a627054..22044297 100644 --- a/python/moose/SBML/readSBML.py +++ b/python/moose/SBML/readSBML.py @@ -13,7 +13,8 @@ ** copyright (C) 2003-2017 Upinder S. Bhalla. and NCBS Created : Thu May 12 10:19:00 2016(+0530) Version -Last-Updated: Tue Feb 10 2017 +Last-Updated: Mon Apr 3 15:50:00 2017(+0530) + By: **********************************************************************/ @@ -23,15 +24,15 @@ import sys import os.path import collections import moose -from validation import validateModel + +from moose.SBML.validation import validateModel + import re ''' TODO in -Compartment - --Need to add group --Need to deal with compartment outside -Molecule - -- Need to add group -- mathML only AssisgmentRule is taken partly I have checked addition and multiplication, --, need to do for other calculation. -- In Assisgment rule one of the variable is a function, in moose since assignment is done using function, @@ -128,17 +129,20 @@ def mooseReadSBML(filepath, loadpath, solver="ee"): warning = " " global msg msg = " " + groupInfo = {} + modelAnnotaInfo = {} comptSbmlidMooseIdMap = {} - #print(("modelPath:" + basePath.path)) globparameterIdValue = {} - modelAnnotaInfo = {} + mapParameter(model, globparameterIdValue) errorFlag = createCompartment( basePath, model, comptSbmlidMooseIdMap) + + groupInfo = checkGroup(basePath,model) if errorFlag: specInfoMap = {} errorFlag,warning = createSpecies( - basePath, model, comptSbmlidMooseIdMap, specInfoMap, modelAnnotaInfo) + basePath, model, comptSbmlidMooseIdMap, specInfoMap, modelAnnotaInfo,groupInfo) #print(errorFlag,warning) if errorFlag: @@ -146,7 +150,7 @@ def mooseReadSBML(filepath, loadpath, solver="ee"): model, specInfoMap, globparameterIdValue) if errorFlag: errorFlag, msg = createReaction( - model, specInfoMap, modelAnnotaInfo, globparameterIdValue) + model, specInfoMap, modelAnnotaInfo, globparameterIdValue,groupInfo) getModelAnnotation( model, baseId, basePath) @@ -164,7 +168,37 @@ def mooseReadSBML(filepath, loadpath, solver="ee"): print("Validation failed while reading the model.") return moose.element('/') +def checkGroup(basePath,model): + groupInfo = {} + modelAnnotaInfo = {} + if model.getPlugin("groups") != None: + mplugin = model.getPlugin("groups") + modelgn = mplugin.getNumGroups() + for gindex in range(0, mplugin.getNumGroups()): + p = mplugin.getGroup(gindex) + groupAnnoInfo = {} + groupAnnoInfo = getObjAnnotation(p, modelAnnotaInfo) + if moose.exists(basePath.path+'/'+groupAnnoInfo["Compartment"]): + if not moose.exists(basePath.path+'/'+groupAnnoInfo["Compartment"]+'/'+p.getId()): + moosegrp = moose.Neutral(basePath.path+'/'+groupAnnoInfo["Compartment"]+'/'+p.getId()) + else: + moosegrp = moose.element(basePath.path+'/'+groupAnnoInfo["Compartment"]+'/'+p.getId()) + moosegrpinfo = moose.Annotator(moosegrp.path+'/info') + moosegrpinfo.color = groupAnnoInfo["bgColor"] + else: + print ("Compartment not found") + + if p.getKind() == 2: + if p.getId() not in groupInfo: + #groupInfo[p.getId()] + for gmemIndex in range(0,p.getNumMembers()): + mem = p.getMember(gmemIndex) + if p.getId() in groupInfo: + groupInfo[p.getId()].append(mem.getIdRef()) + else: + groupInfo[p.getId()] =[mem.getIdRef()] + return groupInfo def setupEnzymaticReaction(enz, groupName, enzName, specInfoMap, modelAnnotaInfo): enzPool = (modelAnnotaInfo[groupName]["enzyme"]) @@ -312,11 +346,11 @@ def getObjAnnotation(obj, modelAnnotationInfo): # modelAnnotaInfo= {} annotateMap = {} if (obj.getAnnotation() is not None): + annoNode = obj.getAnnotation() for ch in range(0, annoNode.getNumChildren()): childNode = annoNode.getChild(ch) - if (childNode.getPrefix() == "moose" and (childNode.getName() == - "ModelAnnotation" or childNode.getName() == "EnzymaticReaction")): + if (childNode.getPrefix() == "moose" and (childNode.getName() in["ModelAnnotation","EnzymaticReaction","GroupAnnotation"])): sublist = [] for gch in range(0, childNode.getNumChildren()): grandChildNode = childNode.getChild(gch) @@ -338,6 +372,8 @@ def getObjAnnotation(obj, modelAnnotationInfo): annotateMap[nodeName] = nodeValue if nodeName == "Group": annotateMap[nodeName] = nodeValue + if nodeName == "Compartment": + annotateMap[nodeName] = nodeValue return annotateMap @@ -443,7 +479,7 @@ def getEnzAnnotation(obj, modelAnnotaInfo, rev, return(groupName) -def createReaction(model, specInfoMap, modelAnnotaInfo, globparameterIdValue): +def createReaction(model, specInfoMap, modelAnnotaInfo, globparameterIdValue,groupInfo): # print " reaction " # Things done for reaction # --Reaction is not created, if substrate and product is missing @@ -467,11 +503,14 @@ def createReaction(model, specInfoMap, modelAnnotaInfo, globparameterIdValue): group = "" reacAnnoInfo = {} reacAnnoInfo = getObjAnnotation(reac, modelAnnotaInfo) - if "Group" in reacAnnoInfo: - group = reacAnnoInfo["Group"] - + # if "Group" in reacAnnoInfo: + # group = reacAnnoInfo["Group"] + if (reac.isSetId()): rId = reac.getId() + groups = [k for k, v in groupInfo.iteritems() if rId in v] + if groups: + group = groups[0] if (reac.isSetName()): rName = reac.getName() rName = rName.replace(" ", "_space_") @@ -817,7 +856,7 @@ def pullnotes(sbmlId, mooseId): def createSpecies(basePath, model, comptSbmlidMooseIdMap, - specInfoMap, modelAnnotaInfo): + specInfoMap, modelAnnotaInfo,groupInfo): # ToDo: # - Need to add group name if exist in pool # - Notes @@ -830,11 +869,16 @@ def createSpecies(basePath, model, comptSbmlidMooseIdMap, group = "" specAnnoInfo = {} specAnnoInfo = getObjAnnotation(spe, modelAnnotaInfo) - if "Group" in specAnnoInfo: - group = specAnnoInfo["Group"] + + # if "Group" in specAnnoInfo: + # group = specAnnoInfo["Group"] sName = None sId = spe.getId() + + groups = [k for k, v in groupInfo.iteritems() if sId in v] + if groups: + group = groups[0] if spe.isSetName(): sName = spe.getName() sName = sName.replace(" ", "_space_") @@ -1161,4 +1205,4 @@ if __name__ == "__main__": if read: print(" Model read to moose path "+ modelpath) else: - print(" could not read SBML to MOOSE") \ No newline at end of file + print(" could not read SBML to MOOSE") diff --git a/python/moose/SBML/writeSBML.py b/python/moose/SBML/writeSBML.py index 90400306..1727d6e6 100644 --- a/python/moose/SBML/writeSBML.py +++ b/python/moose/SBML/writeSBML.py @@ -12,7 +12,7 @@ ** copyright (C) 2003-2017 Upinder S. Bhalla. and NCBS Created : Friday May 27 12:19:00 2016(+0530) Version -Last-Updated: Wed Jan 11 15:20:00 2017(+0530) +Last-Updated: Tue Apr 4 14:20:00 2017(+0530) By: **********************************************************************/ /**************************** @@ -21,16 +21,14 @@ Last-Updated: Wed Jan 11 15:20:00 2017(+0530) import sys import re from collections import Counter - import moose -from validation import validateModel +from moose.SBML.validation import validateModel from moose.chemUtil.chemConnectUtil import * from moose.chemUtil.graphUtils import * # ToDo: # Table should be written -# Group's should be added # boundary condition for buffer pool having assignment statment constant # shd be false @@ -52,7 +50,7 @@ def mooseWriteSBML(modelpath, filename, sceneitems={}): ) return -2, "Could not save the model in to SBML file. \nThis module can be installed by following command in terminal: \n\t easy_install python-libsbml or \n\t apt-get install python-libsbml",'' - sbmlDoc = SBMLDocument(3, 1) + #sbmlDoc = SBMLDocument(3, 1) filepath, filenameExt = os.path.split(filename) if filenameExt.find('.') != -1: filename = filenameExt[:filenameExt.find('.')] @@ -66,16 +64,22 @@ def mooseWriteSBML(modelpath, filename, sceneitems={}): global nameList_ nameList_ = [] positionInfoexist = False - xmlns = XMLNamespaces() - xmlns.add("http://www.sbml.org/sbml/level3/version1") - xmlns.add("http://www.moose.ncbs.res.in", "moose") - xmlns.add("http://www.w3.org/1999/xhtml", "xhtml") - sbmlDoc.setNamespaces(xmlns) + + xmlns = SBMLNamespaces(3, 1) + xmlns.addNamespace("http://www.w3.org/1999/xhtml", "xhtml") + xmlns.addNamespace("http://www.moose.ncbs.res.in", "moose") + xmlns.addNamespace("http://www.sbml.org/sbml/level3/version1/groups/version1", "groups") + sbmlDoc = SBMLDocument(xmlns) + sbmlDoc.setPackageRequired("groups",bool(0)) + cremodel_ = sbmlDoc.createModel() cremodel_.setId(filename) - cremodel_.setTimeUnits("second") + cremodel_.setTimeUnits("time") cremodel_.setExtentUnits("substance") cremodel_.setSubstanceUnits("substance") + cremodel_.setVolumeUnits("volume") + cremodel_.setAreaUnits("area") + cremodel_.setLengthUnits("length") neutralNotes = "" specieslist = moose.wildcardFind(modelpath + '/##[ISA=PoolBase]') @@ -102,14 +106,36 @@ def mooseWriteSBML(modelpath, filename, sceneitems={}): modelAnno = writeSimulationAnnotation(modelpath) if modelAnno: cremodel_.setAnnotation(modelAnno) - - compartexist = writeCompt(modelpath, cremodel_) + groupInfo = {} + compartexist, groupInfo = writeCompt(modelpath, cremodel_) + if compartexist == True: - species = writeSpecies( modelpath,cremodel_,sbmlDoc,sceneitems) + species = writeSpecies( modelpath,cremodel_,sbmlDoc,sceneitems,groupInfo) if species: writeFunc(modelpath, cremodel_) - writeReac(modelpath, cremodel_, sceneitems) - writeEnz(modelpath, cremodel_, sceneitems) + reacGroup = {} + writeReac(modelpath, cremodel_, sceneitems,groupInfo) + writeEnz(modelpath, cremodel_, sceneitems,groupInfo) + if groupInfo: + for key,value in groupInfo.items(): + mplugin = cremodel_.getPlugin("groups") + group = mplugin.createGroup() + name = moose.element(key).name + group.setId(name) + group.setKind("collection") + ginfo = moose.element(key.path+'/info') + groupCompartment = findCompartment(key) + if ginfo.color != '': + grpAnno = "<moose:GroupAnnotation>" + grpAnno = grpAnno + "<moose:Compartment>" + groupCompartment.name + "</moose:Compartment>\n" + if ginfo.color: + grpAnno = grpAnno + "<moose:bgColor>" + ginfo.color + "</moose:bgColor>\n" + grpAnno = grpAnno + "</moose:GroupAnnotation>" + group.setAnnotation(grpAnno) + + for values in value: + member = group.createMember() + member.setIdRef(values) consistencyMessages = "" SBMLok = validateModel(sbmlDoc) if (SBMLok): @@ -127,7 +153,7 @@ def calPrime(x): prime = int((20 * (float(x - cmin) / float(cmax - cmin))) - 10) return prime -def writeEnz(modelpath, cremodel_, sceneitems): +def writeEnz(modelpath, cremodel_, sceneitems,groupInfo): for enz in moose.wildcardFind(modelpath + '/##[ISA=EnzBase]'): enzannoexist = False enzGpnCorCol = " " @@ -135,17 +161,25 @@ def writeEnz(modelpath, cremodel_, sceneitems): enzSubt = () compt = "" notesE = "" + if moose.exists(enz.path + '/info'): + groupName = moose.element("/") Anno = moose.Annotator(enz.path + '/info') notesE = Anno.notes element = moose.element(enz) ele = getGroupinfo(element) - if element.className == "Neutral" or sceneitems or Anno.x or Anno.y: + ele = findGroup_compt(element) + if ele.className == "Neutral" or sceneitems or Anno.x or Anno.y: enzannoexist = True if enzannoexist: enzAnno = "<moose:ModelAnnotation>\n" if ele.className == "Neutral": - enzGpnCorCol = "<moose:Group>" + ele.name + "</moose:Group>\n" + groupName = ele + #enzGpnCorCol = "<moose:Group>" + ele.name + "</moose:Group>\n" + # if ele.name not in groupInfo: + # groupInfo[ele.name]=[setId] + # else: + # groupInfo[ele.name].append(setId) if sceneitems: #Saved from GUI, then scene co-ordinates are passed enzGpnCorCol = enzGpnCorCol + "<moose:xCord>" + \ @@ -165,7 +199,6 @@ def writeEnz(modelpath, cremodel_, sceneitems): if Anno.textColor: enzGpnCorCol = enzGpnCorCol + "<moose:textColor>" + \ Anno.textColor + "</moose:textColor>\n" - if (enz.className == "Enz" or enz.className == "ZombieEnz"): enzyme = cremodel_.createReaction() if notesE != "": @@ -180,14 +213,20 @@ def writeEnz(modelpath, cremodel_, sceneitems): compt = comptVec.name + "_" + \ str(comptVec.getId().value) + "_" + \ str(comptVec.getDataIndex()) + "_" - - enzyme.setId(str(idBeginWith(cleanEnzname + + enzsetId = str(idBeginWith(cleanEnzname + "_" + str(enz.getId().value) + "_" + str(enz.getDataIndex()) + "_" + - "Complex_formation_"))) + "Complex_formation_")) + enzyme.setId(enzsetId) + + if groupName != moose.element('/'): + if groupName not in groupInfo: + groupInfo[groupName]=[enzsetId] + else: + groupInfo[groupName].append(enzsetId) enzyme.setName(cleanEnzname) enzyme.setFast(False) enzyme.setReversible(True) @@ -228,7 +267,7 @@ def writeEnz(modelpath, cremodel_, sceneitems): noofSub, sRateLaw = getSubprd(cremodel_, True, "sub", enzSubt) #rec_order = rec_order + noofSub rec_order = noofSub - rate_law = compt + " * " + rate_law + "*" + sRateLaw + rate_law = compt + " * ( " + rate_law + " * " + sRateLaw enzPrd = enz.neighbors["cplxDest"] if not enzPrd: @@ -238,7 +277,7 @@ def writeEnz(modelpath, cremodel_, sceneitems): for i in range(0, len(nameList_)): enzAnno = enzAnno + "<moose:product>" + \ nameList_[i] + "</moose:product>\n" - rate_law = rate_law + " - " + compt + "* k2" + '*' + sRateLaw + rate_law = rate_law + " - " + " k2 " + ' * ' + sRateLaw +" )" prd_order = noofPrd enzAnno = enzAnno + "<moose:groupName>" + cleanEnzname + "_" + \ @@ -261,14 +300,21 @@ def writeEnz(modelpath, cremodel_, sceneitems): unit = parmUnit(rec_order - 1, cremodel_) printParameters(kl, "k1", k1, unit) enzyme = cremodel_.createReaction() - enzyme.setId(str(idBeginWith(cleanEnzname + + enzsetIdP = str(idBeginWith(cleanEnzname + "_" + str(enz.getId().value) + "_" + str(enz.getDataIndex()) + "_" + - "Product_formation_"))) + "Product_formation_")) + enzyme.setId(enzsetIdP) enzyme.setName(cleanEnzname) + if groupName != moose.element('/'): + if groupName not in groupInfo: + groupInfo[groupName]=[enzsetIdP] + else: + groupInfo[groupName].append(enzsetIdP) + enzyme.setFast(False) enzyme.setReversible(False) enzAnno2 = "<moose:EnzymaticReaction>" @@ -318,6 +364,7 @@ def writeEnz(modelpath, cremodel_, sceneitems): printParameters(kl, "k3", k3, unit) elif(enz.className == "MMenz" or enz.className == "ZombieMMenz"): + enzSub = enz.neighbors["sub"] enzPrd = enz.neighbors["prd"] if (len(enzSub) != 0 and len(enzPrd) != 0): @@ -335,12 +382,18 @@ def writeEnz(modelpath, cremodel_, sceneitems): notesStringE = "<body xmlns=\"http://www.w3.org/1999/xhtml\">\n \t \t" + \ cleanNotesE + "\n\t </body>" enzyme.setNotes(notesStringE) - enzyme.setId(str(idBeginWith(cleanEnzname + + mmenzsetId = str(idBeginWith(cleanEnzname + "_" + str(enz.getId().value) + "_" + str(enz.getDataIndex()) + - "_"))) + "_")) + enzyme.setId(mmenzsetId) + if groupName != moose.element('/'): + if groupName not in groupInfo: + groupInfo[groupName]=[mmenzsetId] + else: + groupInfo[groupName].append(mmenzsetId) enzyme.setName(cleanEnzname) enzyme.setFast(False) enzyme.setReversible(True) @@ -360,14 +413,15 @@ def writeEnz(modelpath, cremodel_, sceneitems): enzPrd = enz.neighbors["prd"] noofPrd, sRateLawP = getSubprd(cremodel_, False, "prd", enzPrd) kl = enzyme.createKineticLaw() - fRate_law = "kcat *" + sRateLawS + "*" + sRateLawM + \ - "/(" + compt + " * (" + "Km" + "+" + sRateLawS + "))" + fRate_law = compt + " * ( kcat * " + sRateLawS + " * " + sRateLawM + \ + " / ( Km" + " + " + sRateLawS + "))" kl.setFormula(fRate_law) kl.setNotes( "<body xmlns=\"http://www.w3.org/1999/xhtml\">\n\t\t" + fRate_law + "\n \t </body>") - printParameters(kl, "Km", Km, "substance") + KmUnit(cremodel_) + printParameters(kl, "Km", Km, "mmole_per_litre") kcatUnit = parmUnit(0, cremodel_) printParameters(kl, "kcat", kcat, kcatUnit) @@ -378,6 +432,29 @@ def printParameters(kl, k, kvalue, unit): para.setValue(kvalue) para.setUnits(unit) +def KmUnit(cremodel_): + unit_stream = "mmole_per_litre" + lud = cremodel_.getListOfUnitDefinitions() + flag = False + for i in range(0, len(lud)): + ud = lud.get(i) + if (ud.getId() == unit_stream): + flag = True + break + if (not flag): + unitdef = cremodel_.createUnitDefinition() + unitdef.setId(unit_stream) + unit = unitdef.createUnit() + unit.setKind(UNIT_KIND_LITRE) + unit.setExponent(-1) + unit.setMultiplier(1) + unit.setScale(0) + unit = unitdef.createUnit() + unit.setKind(UNIT_KIND_MOLE) + unit.setExponent(1) + unit.setMultiplier(1) + unit.setScale(-3) + return unit_stream def parmUnit(rct_order, cremodel_): order = rct_order @@ -386,7 +463,7 @@ def parmUnit(rct_order, cremodel_): elif order == 1: unit_stream = "litre_per_mmole_per_second" elif order == 2: - unit_stream = "litre_per_mmole_sq_per_second" + unit_stream = "sq_litre_per_mmole_sq_per_second" else: unit_stream = "litre_per_mmole_" + str(rct_order) + "_per_second" @@ -405,7 +482,7 @@ def parmUnit(rct_order, cremodel_): if order != 0: unit = unitdef.createUnit() unit.setKind(UNIT_KIND_LITRE) - unit.setExponent(1) + unit.setExponent(order) unit.setMultiplier(1) unit.setScale(0) unit = unitdef.createUnit() @@ -507,7 +584,7 @@ def listofname(reacSub, mobjEnz): nameList_.append(clean_name) -def writeReac(modelpath, cremodel_, sceneitems): +def writeReac(modelpath, cremodel_, sceneitems,reacGroup): for reac in moose.wildcardFind(modelpath + '/##[ISA=ReacBase]'): reacSub = reac.neighbors["sub"] reacPrd = reac.neighbors["prd"] @@ -517,12 +594,13 @@ def writeReac(modelpath, cremodel_, sceneitems): reacannoexist = False reacGpname = " " cleanReacname = convertSpecialChar(reac.name) - reaction.setId(str(idBeginWith(cleanReacname + + setId = str(idBeginWith(cleanReacname + "_" + str(reac.getId().value) + "_" + str(reac.getDataIndex()) + - "_"))) + "_")) + reaction.setId(setId) reaction.setName(cleanReacname) #Kf = reac.numKf #Kb = reac.numKb @@ -548,7 +626,11 @@ def writeReac(modelpath, cremodel_, sceneitems): if reacannoexist: reacAnno = "<moose:ModelAnnotation>\n" if ele.className == "Neutral": - reacAnno = reacAnno + "<moose:Group>" + ele.name + "</moose:Group>\n" + #reacAnno = reacAnno + "<moose:Group>" + ele.name + "</moose:Group>\n" + if ele not in reacGroup: + reacGroup[ele]=[setId] + else: + reacGroup[ele].append(setId) if sceneitems: #Saved from GUI, then scene co-ordinates are passed reacAnno = reacAnno + "<moose:xCord>" + \ @@ -629,6 +711,7 @@ def writeReac(modelpath, cremodel_, sceneitems): kl_s + "\n \t </body>") kfl.setFormula(kl_s) + else: print(" Reaction ", reac.name, "missing substrate and product") @@ -667,7 +750,6 @@ def writeFunc(modelpath, cremodel_): rule.setVariable(fName) rule.setFormula(expr) - def convertNotesSpecialChar(str1): d = {"&": "_and", "<": "_lessthan_", ">": "_greaterthan_", "BEL": "°"} for i, j in d.items(): @@ -676,7 +758,6 @@ def convertNotesSpecialChar(str1): str1 = str1.strip(' \t\n\r') return str1 - def getGroupinfo(element): # Note: At this time I am assuming that if group exist (incase of Genesis) # 1. for 'pool' its between compartment and pool, /modelpath/Compartment/Group/pool @@ -685,8 +766,7 @@ def getGroupinfo(element): # if /modelpath/Compartment/Group/Group1/Pool, then I check and get Group1 # And /modelpath is also a NeutralObject,I stop till I find Compartment - while not mooseIsInstance(element, ["Neutral"]) and not mooseIsInstance( - element, ["CubeMesh", "CyclMesh"]): + while not mooseIsInstance(element, ["Neutral", "CubeMesh", "CyclMesh"]): element = element.parent return element @@ -707,6 +787,10 @@ def idBeginWith(name): changedName = "_" + name return changedName +def findGroup_compt(melement): + while not (mooseIsInstance(melement, ["Neutral","CubeMesh", "CyclMesh"])): + melement = melement.parent + return melement def convertSpecialChar(str1): d = {"&": "_and", "<": "_lessthan_", ">": "_greaterthan_", "BEL": "°", "-": "_minus_", "'": "_prime_", @@ -718,7 +802,7 @@ def convertSpecialChar(str1): return str1 -def writeSpecies(modelpath, cremodel_, sbmlDoc, sceneitems): +def writeSpecies(modelpath, cremodel_, sbmlDoc, sceneitems,speGroup): # getting all the species for spe in moose.wildcardFind(modelpath + '/##[ISA=PoolBase]'): sName = convertSpecialChar(spe.name) @@ -798,7 +882,13 @@ def writeSpecies(modelpath, cremodel_, sbmlDoc, sceneitems): if speciannoexist: speciAnno = "<moose:ModelAnnotation>\n" if ele.className == "Neutral": - speciAnno = speciAnno + "<moose:Group>" + ele.name + "</moose:Group>\n" + #speciAnno = speciAnno + "<moose:Group>" + ele.name + "</moose:Group>\n" + if ele not in speGroup: + speGroup[ele]=[spename] + else: + speGroup[ele].append(spename) + + if sceneitems: #Saved from GUI, then scene co-ordinates are passed speciAnno = speciAnno + "<moose:xCord>" + \ @@ -826,6 +916,7 @@ def writeSpecies(modelpath, cremodel_, sbmlDoc, sceneitems): def writeCompt(modelpath, cremodel_): # getting all the compartments compts = moose.wildcardFind(modelpath + '/##[ISA=ChemCompt]') + groupInfo = {} for compt in compts: comptName = convertSpecialChar(compt.name) # converting m3 to litre @@ -843,10 +934,20 @@ def writeCompt(modelpath, cremodel_): c1.setSize(size) c1.setSpatialDimensions(ndim) c1.setUnits('volume') + #For each compartment get groups information along + for grp in moose.wildcardFind(compt.path+'/##[TYPE=Neutral]'): + grp_cmpt = findGroup_compt(grp.parent) + try: + value = groupInfo[moose.element(grp)] + except KeyError: + # Grp is not present + groupInfo[moose.element(grp)] = [] + + if compts: - return True + return True,groupInfo else: - return False + return False,groupInfo # write Simulation runtime,simdt,plotdt def writeSimulationAnnotation(modelpath): modelAnno = "" @@ -905,6 +1006,30 @@ def writeUnits(cremodel_): unit.setExponent(1.0) unit.setScale(-3) + unitLen = cremodel_.createUnitDefinition() + unitLen.setId("length") + unit = unitLen.createUnit() + unit.setKind(UNIT_KIND_METRE) + unit.setMultiplier(1.0) + unit.setExponent(1.0) + unit.setScale(0) + + unitArea = cremodel_.createUnitDefinition() + unitArea.setId("area") + unit = unitArea.createUnit() + unit.setKind(UNIT_KIND_METRE) + unit.setMultiplier(1.0) + unit.setExponent(2.0) + unit.setScale(0) + + unitTime = cremodel_.createUnitDefinition() + unitTime.setId("time") + unit = unitTime.createUnit() + unit.setKind(UNIT_KIND_SECOND) + unit.setExponent(1) + unit.setMultiplier(1) + unit.setScale(0) + if __name__ == "__main__": try: sys.argv[1] diff --git a/python/moose/__init__.py b/python/moose/__init__.py index 2e2f6772..02f1c5e6 100644 --- a/python/moose/__init__.py +++ b/python/moose/__init__.py @@ -1,32 +1,506 @@ +"""__init__.py: + """ -How to use the documentation ----------------------------- -MOOSE documentation is split into Python documentation and builtin -documentation. The functions and classes that are only part of the -Python interface can be viewed via Python's builtin ``help`` -function:: +from __future__ import print_function +from __future__ import absolute_import + ->>> help(moose.connect) +from contextlib import closing +import warnings +import platform +import pydoc +import os +from io import StringIO +from collections import defaultdict -The documentation built into main C++ code of MOOSE can be accessed -via the module function ``doc``:: +import moose +from moose._moose import * +import moose.SBML ->>> moose.doc('Neutral') +# Wrapper to get moose version information. +__version__ = moose._moose.__version__ +VERSION = moose._moose.VERSION -To get documentation about a particular field:: +sequence_types = ['vector<double>', + 'vector<int>', + 'vector<long>', + 'vector<unsigned int>', + 'vector<float>', + 'vector<unsigned long>', + 'vector<short>', + 'vector<Id>', + 'vector<ObjId>'] ->>> moose.doc('Neutral.childMsg') +known_types = ['void', + 'char', + 'short', + 'int', + 'unsigned int', + 'double', + 'float', + 'long', + 'unsigned long', + 'string', + 'vec', + 'melement'] + sequence_types -Builtin functions and classes in moose module (Python only) ------------------------------------------------------------ +# SBML related functions. -""" -from .moose import * +def mooseReadSBML(filepath, loadpath, solver='ee'): + """Load SBML model. -# Wrapper to get moose version information. -__version__ = moose._moose.__version__ + keyword arguments: \n -VERSION = moose._moose.VERSION + filepath -- filepath to be loaded \n + loadpath -- Root path for this model e.g. /model/mymodel \n + solver -- Solver to use (default 'ee' ) \n + + """ + return moose.SBML.readSBML.mooseReadSBML( filepath, loadpath, solver ) + + +def mooseWriteSBML(modelpath, filepath, sceneitems={}): + """Writes loaded model under modelpath to a file in SBML format. + + keyword arguments:\n + + modelpath -- model path in moose e.g /model/mymodel \n + filepath -- Path of output file. \n + sceneitems -- dictlist (UserWarning: user need not worry about this) \n + layout position is saved in Annotation field of all the moose Object (pool,Reaction,enzyme)\n + If this function is called from \n + -- GUI, the layout position of moose object is passed \n + -- command line, \n + ---if genesis/kkit model is loaded then layout position is taken from the file \n + --- else, auto-coordinates is used for layout position and passed + + """ + return moose.SBML.writeSBML.mooseWriteSBML(modelpath, filepath, sceneitems) + + +def mooseWriteKkit(modelpath, filepath,sceneitems={}): + """Writes loded model under modelpath to a file in Kkit format. + + keyword arguments:\n + + modelpath -- model path in moose \n + filepath -- Path of output file. + """ + return moose.genesis.writeKkit.mooseWriteKkit(modelpath, filepath,sceneitems) + + +def moosedeleteChemSolver(modelpath): + """ deletes solver on all the compartment and its children. + This is neccesary while created a new moose object on a pre-existing modelpath,\n + this should be followed by mooseaddChemSolver for add solvers on to compartment to simulate else + default is Exponential Euler (ee) + """ + return chemUtil.add_Delete_ChemicalSolver.moosedeleteChemSolver(modelpath) + + +def mooseaddChemSolver(modelpath, solver): + """ Add solver on chemical compartment and its children for calculation + + keyword arguments:\n + + modelpath -- model path that is loaded into moose \n + solver -- "Exponential Euler" (ee) (default), \n + "Gillespie" ("gssa"), \n + "Runge Kutta" ("gsl") + + """ + return chemUtil.add_Delete_ChemicalSolver.mooseaddChemSolver(modelpath, solver) + +################################################################ +# Wrappers for global functions +################################################################ + + +def pwe(): + """Print present working element. Convenience function for GENESIS + users. If you want to retrieve the element in stead of printing + the path, use moose.getCwe() + + """ + pwe_ = _moose.getCwe() + print(pwe_.getPath()) + return pwe_ + + +def le(el=None): + """List elements under `el` or current element if no argument + specified. + + Parameters + ---------- + el : str/melement/vec/None + The element or the path under which to look. If `None`, children + of current working element are displayed. + + Returns + ------- + List of path of child elements + + """ + if el is None: + el = getCwe() + elif isinstance(el, str): + if not exists(el): + raise ValueError('no such element') + el = element(el) + elif isinstance(el, vec): + el = el[0] + print('Elements under', el.path) + for ch in el.children: + print(ch.path) + return [child.path for child in el.children] + +ce = setCwe # ce is a GENESIS shorthand for change element. + + +def syncDataHandler(target): + """Synchronize data handlers for target. + + Parameters + ---------- + target : melement/vec/str + Target element or vec or path string. + + Raises + ------ + NotImplementedError + The call to the underlying C++ function does not work. + + Notes + ----- + This function is defined for completeness, but currently it does not work. + + """ + raise NotImplementedError('The implementation is not working for IntFire - goes to invalid objects. \ +First fix that issue with SynBase or something in that line.') + if isinstance(target, str): + if not _moose.exists(target): + raise ValueError('%s: element does not exist.' % (target)) + target = vec(target) + _moose.syncDataHandler(target) + + +def showfield(el, field='*', showtype=False): + """Show the fields of the element `el`, their data types and + values in human readable format. Convenience function for GENESIS + users. + + Parameters + ---------- + el : melement/str + Element or path of an existing element. + + field : str + Field to be displayed. If '*' (default), all fields are displayed. + + showtype : bool + If True show the data type of each field. False by default. + + Returns + ------- + None + + """ + if isinstance(el, str): + if not exists(el): + raise ValueError('no such element') + el = element(el) + if field == '*': + value_field_dict = getFieldDict(el.className, 'valueFinfo') + max_type_len = max(len(dtype) for dtype in value_field_dict.values()) + max_field_len = max(len(dtype) for dtype in value_field_dict.keys()) + print('\n[', el.path, ']') + for key, dtype in sorted(value_field_dict.items()): + if dtype == 'bad' or key == 'this' or key == 'dummy' or key == 'me' or dtype.startswith( + 'vector') or 'ObjId' in dtype: + continue + value = el.getField(key) + if showtype: + typestr = dtype.ljust(max_type_len + 4) + # The following hack is for handling both Python 2 and + # 3. Directly putting the print command in the if/else + # clause causes syntax error in both systems. + print(typestr, end=' ') + print(key.ljust(max_field_len + 4), '=', value) + else: + try: + print(field, '=', el.getField(field)) + except AttributeError: + pass # Genesis silently ignores non existent fields + + +def showfields(el, showtype=False): + """Convenience function. Should be deprecated if nobody uses it. + + """ + warnings.warn( + 'Deprecated. Use showfield(element, field="*", showtype=True) instead.', + DeprecationWarning) + showfield(el, field='*', showtype=showtype) + +# Predefined field types and their human readable names +finfotypes = [('valueFinfo', 'value field'), + ('srcFinfo', 'source message field'), + ('destFinfo', 'destination message field'), + ('sharedFinfo', 'shared message field'), + ('lookupFinfo', 'lookup field')] + + +def listmsg(el): + """Return a list containing the incoming and outgoing messages of + `el`. + + Parameters + ---------- + el : melement/vec/str + MOOSE object or path of the object to look into. + + Returns + ------- + msg : list + List of Msg objects corresponding to incoming and outgoing + connections of `el`. + + """ + obj = element(el) + ret = [] + for msg in obj.inMsg: + ret.append(msg) + for msg in obj.outMsg: + ret.append(msg) + return ret + + +def showmsg(el): + """Print the incoming and outgoing messages of `el`. + + Parameters + ---------- + el : melement/vec/str + Object whose messages are to be displayed. + + Returns + ------- + None + + """ + obj = element(el) + print('INCOMING:') + for msg in obj.msgIn: + print( + msg.e2.path, + msg.destFieldsOnE2, + '<---', + msg.e1.path, + msg.srcFieldsOnE1) + print('OUTGOING:') + for msg in obj.msgOut: + print( + msg.e1.path, + msg.srcFieldsOnE1, + '--->', + msg.e2.path, + msg.destFieldsOnE2) + + +def getfielddoc(tokens, indent=''): + """Return the documentation for field specified by `tokens`. + + Parameters + ---------- + tokens : (className, fieldName) str + A sequence whose first element is a MOOSE class name and second + is the field name. + + indent : str + indentation (default: empty string) prepended to builtin + documentation string. + + Returns + ------- + docstring : str + string of the form + `{indent}{className}.{fieldName}: {datatype} - {finfoType}\n{Description}\n` + + Raises + ------ + NameError + If the specified fieldName is not present in the specified class. + """ + assert(len(tokens) > 1) + classname = tokens[0] + fieldname = tokens[1] + while True: + try: + classelement = _moose.element('/classes/' + classname) + for finfo in classelement.children: + for fieldelement in finfo: + baseinfo = '' + if classname != tokens[0]: + baseinfo = ' (inherited from {})'.format(classname) + if fieldelement.fieldName == fieldname: + # The field elements are + # /classes/{ParentClass}[0]/{fieldElementType}[N]. + finfotype = fieldelement.name + return '{indent}{classname}.{fieldname}: type={type}, finfotype={finfotype}{baseinfo}\n\t{docs}\n'.format( + indent=indent, classname=tokens[0], + fieldname=fieldname, + type=fieldelement.type, + finfotype=finfotype, + baseinfo=baseinfo, + docs=fieldelement.docs) + classname = classelement.baseClass + except ValueError: + raise NameError('`%s` has no field called `%s`' + % (tokens[0], tokens[1])) + + +def toUnicode(v, encoding='utf8'): + # if isinstance(v, str): + # return v + try: + return v.decode(encoding) + except (AttributeError, UnicodeEncodeError): + return str(v) + + +def getmoosedoc(tokens, inherited=False): + """Return MOOSE builtin documentation. + + Parameters + ---------- + tokens : (className, [fieldName]) + tuple containing one or two strings specifying class name + and field name (optional) to get documentation for. + + inherited: bool (default: False) + include inherited fields. + + Returns + ------- + docstring : str + Documentation string for class `className`.`fieldName` if both + are specified, for the class `className` if fieldName is not + specified. In the latter case, the fields and their data types + and finfo types are listed. + + Raises + ------ + NameError + If class or field does not exist. + + """ + indent = ' ' + with closing(StringIO()) as docstring: + if not tokens: + return "" + try: + class_element = _moose.element('/classes/%s' % (tokens[0])) + except ValueError: + raise NameError('name \'%s\' not defined.' % (tokens[0])) + if len(tokens) > 1: + docstring.write(toUnicode(getfielddoc(tokens))) + else: + docstring.write(toUnicode('%s\n' % (class_element.docs))) + append_finfodocs(tokens[0], docstring, indent) + if inherited: + mro = eval('_moose.%s' % (tokens[0])).mro() + for class_ in mro[1:]: + if class_ == _moose.melement: + break + docstring.write(toUnicode( + '\n\n#Inherited from %s#\n' % (class_.__name__))) + append_finfodocs(class_.__name__, docstring, indent) + if class_ == _moose.Neutral: # Neutral is the toplevel moose class + break + return docstring.getvalue() + + +def append_finfodocs(classname, docstring, indent): + """Append list of finfos in class name to docstring""" + try: + class_element = _moose.element('/classes/%s' % (classname)) + except ValueError: + raise NameError('class \'%s\' not defined.' % (classname)) + for ftype, rname in finfotypes: + docstring.write(toUnicode('\n*%s*\n' % (rname.capitalize()))) + try: + finfo = _moose.element('%s/%s' % (class_element.path, ftype)) + for field in finfo.vec: + docstring.write(toUnicode( + '%s%s: %s\n' % (indent, field.fieldName, field.type))) + except ValueError: + docstring.write(toUnicode('%sNone\n' % (indent))) + + +# the global pager is set from pydoc even if the user asks for paged +# help once. this is to strike a balance between GENESIS user's +# expectation of control returning to command line after printing the +# help and python user's expectation of seeing the help via more/less. +pager = None + + +def doc(arg, inherited=True, paged=True): + """Display the documentation for class or field in a class. + + Parameters + ---------- + arg : str/class/melement/vec + A string specifying a moose class name and a field name + separated by a dot. e.g., 'Neutral.name'. Prepending `moose.` + is allowed. Thus moose.doc('moose.Neutral.name') is equivalent + to the above. + It can also be string specifying just a moose class name or a + moose class or a moose object (instance of melement or vec + or there subclasses). In that case, the builtin documentation + for the corresponding moose class is displayed. + + paged: bool + Whether to display the docs via builtin pager or print and + exit. If not specified, it defaults to False and + moose.doc(xyz) will print help on xyz and return control to + command line. + + Returns + ------- + None + + Raises + ------ + NameError + If class or field does not exist. + + """ + # There is no way to dynamically access the MOOSE docs using + # pydoc. (using properties requires copying all the docs strings + # from MOOSE increasing the loading time by ~3x). Hence we provide a + # separate function. + global pager + if paged and pager is None: + pager = pydoc.pager + tokens = [] + text = '' + if isinstance(arg, str): + tokens = arg.split('.') + if tokens[0] == 'moose': + tokens = tokens[1:] + elif isinstance(arg, type): + tokens = [arg.__name__] + elif isinstance(arg, melement) or isinstance(arg, vec): + text = '%s: %s\n\n' % (arg.path, arg.className) + tokens = [arg.className] + if tokens: + text += getmoosedoc(tokens, inherited=inherited) + else: + text += pydoc.getdoc(arg) + if pager: + pager(text) + else: + print(text) -# NOTE: No module should be imported here. Use moose.py to write imports. diff --git a/python/moose/merge/merge.py b/python/moose/merge/merge.py index 02ecc805..ee940162 100644 --- a/python/moose/merge/merge.py +++ b/python/moose/merge/merge.py @@ -11,15 +11,31 @@ #** copyright (C) 2003-2017 Upinder S. Bhalla. and NCBS #Created : Friday Dec 16 23:19:00 2016(+0530) #Version -#Last-Updated: Thursday Jan 12 17:30:33 2017(+0530) +#Last-Updated: Tuesday Feb 28 15:05:33 2017(+0530) # By: Harsha #**********************************************************************/ -# This program is used to merge models -# -- Model B is merged to modelA -#Rules are -#--In this models are mergered at group level (if exists) - +# This program is used to merge models from src to destination +#Rules are : +# -- If Compartment from the src model doesn't exist in destination model, +# then entire compartment and its children are copied over including groups +# -- Models are mergered at group level (if exists) +# (Group is Neutral object in moose, which may represent pathway in network model) +# -- Pool's are copied from source to destination if it doesn't exist, if exist nothing is done +# -- Reaction (Reac), Enzyme (Enz) are copied +# --- if any danglling Reac or Enz exist then that is not copied +# +# --- if Reac Name's is different for a given path (group level) +# then copy the entire Reac along with substrate/product +# --- if same Reac Name and same sub and prd then nothing is copied +# --- if same Reac Name but sub or prd is different then duplicated and copied +# +# --- if Enz Name's is different for a given parent pool path +# then copy the entire Enz along with substrate/product +# --- if same Enz Name and same sub and prd then nothing is copied +# --- if same Enz Name but sub or prd is different then duplicated and copied +# -- Function are copied only if destination pool to which its suppose to connect doesn't exist with function of its own +# import sys @@ -31,8 +47,11 @@ import mtypes from moose.chemUtil.chemConnectUtil import * from moose.chemUtil.graphUtils import * -def mergeChemModel(A,B): +def mergeChemModel(src,des): + """ Merges two model or the path """ + A = src + B = des loadedA = False loadedB = False @@ -103,21 +122,22 @@ def mergeChemModel(A,B): poolListinb = updatePoolList(dictComptB) E_Duplicated,E_Notcopiedyet,E_Daggling = enzymeMerge(dictComptB,dictComptA,key,poolListinb) - - print("\n Model is merged to %s" %modelB) + path, sfile = os.path.split(src) + path, dfile = os.path.split(des) + print("\n %s (src) model is merged to %s (des)" %(sfile, dfile)) if funcExist: - print( "\nPool already connected to a function, this function is not to connect to same pool, since no two function are allowed to connect to same pool:") + print( "\nIn model \"%s\" pool already has connection from a function, these function from model \"%s\" is not allowed to connect to same pool,\n since no two function are allowed to connect to same pool:"%(dfile, sfile)) for fl in list(funcExist): print("\t [Pool]: %s [Function]: %s \n" %(str(fl.parent.name), str(fl.path))) if funcNotallowed: - print( "\nThis function is not to copied, since pool connected to function input are from different compartment:") + print( "\nThese functions is not to copied, since pool connected to function input are from different compartment:") for fl in list(funcNotallowed): print("\t [Pool]: %s [Function]: %s \n" %(str(fl.parent.name), str(fl.path))) if R_Duplicated or E_Duplicated: - print ("Reaction / Enzyme are Duplicate" - "\n 1. The once whoes substrate / product names are different for a give reaction name " - "\n 2. its compartment to which it belongs to may be is different" - "\n Models have to decide to keep or delete these reaction/enzyme") + print ("These Reaction / Enzyme are \"Duplicated\" into destination file \"%s\", due to " + "\n 1. If substrate / product name's are different for a give reaction/Enzyme name " + "\n 2. If product belongs to different compartment " + "\n Models have to decide to keep or delete these reaction/enzyme in %s" %(dfile, dfile)) if E_Duplicated: print("Reaction: ") for rd in list(R_Duplicated): @@ -141,7 +161,7 @@ def mergeChemModel(A,B): print ("%s " %str(ed.name)) if R_Daggling or E_Daggling: - print ("\n Daggling reaction/enzyme are not not allowed in moose, these are not merged") + print ("\n Daggling reaction/enzyme are not allowed in moose, these are not merged to %s from %s" %(dfile, sfile)) if R_Daggling: print("Reaction: ") for rd in list(R_Daggling): @@ -596,7 +616,24 @@ def mooseIsInstance(element, classNames): if __name__ == "__main__": - - modelA = 'acc50.g' - modelB = 'acc92.g' - mergered = mergeChemModel(modelA,modelB) + try: + sys.argv[1] + except IndexError: + print("Source filename or path not given") + exit(0) + else: + src = sys.argv[1] + if not os.path.exists(src): + print("Filename or path does not exist",src) + else: + try: + sys.argv[2] + except IndexError: + print("Destination filename or path not given") + exit(0) + else: + des = sys.argv[2] + if not os.path.exists(src): + print("Filename or path does not exist",des) + exit(0) + mergered = mergeChemModel(src,des) \ No newline at end of file diff --git a/python/moose/moose.py b/python/moose/moose.py deleted file mode 100644 index 1309c68f..00000000 --- a/python/moose/moose.py +++ /dev/null @@ -1,508 +0,0 @@ -# moose.py --- -# This is the primary moose module. It wraps _moose.so and adds some -# utility functions. - -# Filename: moose.py -# Author: Subhasis Ray -# Maintainer: Dilawar Singh, Harsha Rani, Upi Bhalla - -from __future__ import print_function -from contextlib import closing -import warnings -import platform -import pydoc -import os -from io import StringIO -from collections import defaultdict -from . import _moose -from ._moose import * -import __main__ as main -import genesis.writeKkit -import SBML.readSBML -import SBML.writeSBML -sequence_types = ['vector<double>', - 'vector<int>', - 'vector<long>', - 'vector<unsigned int>', - 'vector<float>', - 'vector<unsigned long>', - 'vector<short>', - 'vector<Id>', - 'vector<ObjId>'] - -known_types = ['void', - 'char', - 'short', - 'int', - 'unsigned int', - 'double', - 'float', - 'long', - 'unsigned long', - 'string', - 'vec', - 'melement'] + sequence_types - -# SBML related functions. - - -def mooseReadSBML(filepath, loadpath, solver='ee'): - """Load SBML model. - - keyword arguments: \n - - filepath -- filepath to be loaded \n - loadpath -- Root path for this model e.g. /model/mymodel \n - solver -- Solver to use (default 'ee' ) \n - - """ - return SBML.readSBML.mooseReadSBML( filepath, loadpath, solver ) - - -def mooseWriteSBML(modelpath, filepath, sceneitems={}): - """Writes loaded model under modelpath to a file in SBML format. - - keyword arguments:\n - - modelpath -- model path in moose e.g /model/mymodel \n - filepath -- Path of output file. \n - sceneitems -- dictlist (UserWarning: user need not worry about this) \n - layout position is saved in Annotation field of all the moose Object (pool,Reaction,enzyme)\n - If this function is called from \n - -- GUI, the layout position of moose object is passed \n - -- command line, \n - ---if genesis/kkit model is loaded then layout position is taken from the file \n - --- else, auto-coordinates is used for layout position and passed - - """ - return SBML.writeSBML.mooseWriteSBML(modelpath, filepath, sceneitems) - - -def mooseWriteKkit(modelpath, filepath,sceneitems={}): - """Writes loded model under modelpath to a file in Kkit format. - - keyword arguments:\n - - modelpath -- model path in moose \n - filepath -- Path of output file. - """ - return genesis.writeKkit.mooseWriteKkit(modelpath, filepath,sceneitems) - - -def moosedeleteChemSolver(modelpath): - """ deletes solver on all the compartment and its children. - This is neccesary while created a new moose object on a pre-existing modelpath,\n - this should be followed by mooseaddChemSolver for add solvers on to compartment to simulate else - default is Exponential Euler (ee) - """ - return chemUtil.add_Delete_ChemicalSolver.moosedeleteChemSolver(modelpath) - - -def mooseaddChemSolver(modelpath, solver): - """ Add solver on chemical compartment and its children for calculation - - keyword arguments:\n - - modelpath -- model path that is loaded into moose \n - solver -- "Exponential Euler" (ee) (default), \n - "Gillespie" ("gssa"), \n - "Runge Kutta" ("gsl") - - """ - return chemUtil.add_Delete_ChemicalSolver.mooseaddChemSolver(modelpath, solver) - -################################################################ -# Wrappers for global functions -################################################################ - - -def pwe(): - """Print present working element. Convenience function for GENESIS - users. If you want to retrieve the element in stead of printing - the path, use moose.getCwe() - - """ - pwe_ = _moose.getCwe() - print(pwe_.getPath()) - return pwe_ - - -def le(el=None): - """List elements under `el` or current element if no argument - specified. - - Parameters - ---------- - el : str/melement/vec/None - The element or the path under which to look. If `None`, children - of current working element are displayed. - - Returns - ------- - List of path of child elements - - """ - if el is None: - el = getCwe() - elif isinstance(el, str): - if not exists(el): - raise ValueError('no such element') - el = element(el) - elif isinstance(el, vec): - el = el[0] - print('Elements under', el.path) - for ch in el.children: - print(ch.path) - return [child.path for child in el.children] - -ce = setCwe # ce is a GENESIS shorthand for change element. - - -def syncDataHandler(target): - """Synchronize data handlers for target. - - Parameters - ---------- - target : melement/vec/str - Target element or vec or path string. - - Raises - ------ - NotImplementedError - The call to the underlying C++ function does not work. - - Notes - ----- - This function is defined for completeness, but currently it does not work. - - """ - raise NotImplementedError('The implementation is not working for IntFire - goes to invalid objects. \ -First fix that issue with SynBase or something in that line.') - if isinstance(target, str): - if not _moose.exists(target): - raise ValueError('%s: element does not exist.' % (target)) - target = vec(target) - _moose.syncDataHandler(target) - - -def showfield(el, field='*', showtype=False): - """Show the fields of the element `el`, their data types and - values in human readable format. Convenience function for GENESIS - users. - - Parameters - ---------- - el : melement/str - Element or path of an existing element. - - field : str - Field to be displayed. If '*' (default), all fields are displayed. - - showtype : bool - If True show the data type of each field. False by default. - - Returns - ------- - None - - """ - if isinstance(el, str): - if not exists(el): - raise ValueError('no such element') - el = element(el) - if field == '*': - value_field_dict = getFieldDict(el.className, 'valueFinfo') - max_type_len = max(len(dtype) for dtype in value_field_dict.values()) - max_field_len = max(len(dtype) for dtype in value_field_dict.keys()) - print('\n[', el.path, ']') - for key, dtype in sorted(value_field_dict.items()): - if dtype == 'bad' or key == 'this' or key == 'dummy' or key == 'me' or dtype.startswith( - 'vector') or 'ObjId' in dtype: - continue - value = el.getField(key) - if showtype: - typestr = dtype.ljust(max_type_len + 4) - # The following hack is for handling both Python 2 and - # 3. Directly putting the print command in the if/else - # clause causes syntax error in both systems. - print(typestr, end=' ') - print(key.ljust(max_field_len + 4), '=', value) - else: - try: - print(field, '=', el.getField(field)) - except AttributeError: - pass # Genesis silently ignores non existent fields - - -def showfields(el, showtype=False): - """Convenience function. Should be deprecated if nobody uses it. - - """ - warnings.warn( - 'Deprecated. Use showfield(element, field="*", showtype=True) instead.', - DeprecationWarning) - showfield(el, field='*', showtype=showtype) - -# Predefined field types and their human readable names -finfotypes = [('valueFinfo', 'value field'), - ('srcFinfo', 'source message field'), - ('destFinfo', 'destination message field'), - ('sharedFinfo', 'shared message field'), - ('lookupFinfo', 'lookup field')] - - -def listmsg(el): - """Return a list containing the incoming and outgoing messages of - `el`. - - Parameters - ---------- - el : melement/vec/str - MOOSE object or path of the object to look into. - - Returns - ------- - msg : list - List of Msg objects corresponding to incoming and outgoing - connections of `el`. - - """ - obj = element(el) - ret = [] - for msg in obj.inMsg: - ret.append(msg) - for msg in obj.outMsg: - ret.append(msg) - return ret - - -def showmsg(el): - """Print the incoming and outgoing messages of `el`. - - Parameters - ---------- - el : melement/vec/str - Object whose messages are to be displayed. - - Returns - ------- - None - - """ - obj = element(el) - print('INCOMING:') - for msg in obj.msgIn: - print( - msg.e2.path, - msg.destFieldsOnE2, - '<---', - msg.e1.path, - msg.srcFieldsOnE1) - print('OUTGOING:') - for msg in obj.msgOut: - print( - msg.e1.path, - msg.srcFieldsOnE1, - '--->', - msg.e2.path, - msg.destFieldsOnE2) - - -def getfielddoc(tokens, indent=''): - """Return the documentation for field specified by `tokens`. - - Parameters - ---------- - tokens : (className, fieldName) str - A sequence whose first element is a MOOSE class name and second - is the field name. - - indent : str - indentation (default: empty string) prepended to builtin - documentation string. - - Returns - ------- - docstring : str - string of the form - `{indent}{className}.{fieldName}: {datatype} - {finfoType}\n{Description}\n` - - Raises - ------ - NameError - If the specified fieldName is not present in the specified class. - """ - assert(len(tokens) > 1) - classname = tokens[0] - fieldname = tokens[1] - while True: - try: - classelement = _moose.element('/classes/' + classname) - for finfo in classelement.children: - for fieldelement in finfo: - baseinfo = '' - if classname != tokens[0]: - baseinfo = ' (inherited from {})'.format(classname) - if fieldelement.fieldName == fieldname: - # The field elements are - # /classes/{ParentClass}[0]/{fieldElementType}[N]. - finfotype = fieldelement.name - return '{indent}{classname}.{fieldname}: type={type}, finfotype={finfotype}{baseinfo}\n\t{docs}\n'.format( - indent=indent, classname=tokens[0], - fieldname=fieldname, - type=fieldelement.type, - finfotype=finfotype, - baseinfo=baseinfo, - docs=fieldelement.docs) - classname = classelement.baseClass - except ValueError: - raise NameError('`%s` has no field called `%s`' - % (tokens[0], tokens[1])) - - -def toUnicode(v, encoding='utf8'): - # if isinstance(v, str): - # return v - try: - return v.decode(encoding) - except (AttributeError, UnicodeEncodeError): - return str(v) - - -def getmoosedoc(tokens, inherited=False): - """Return MOOSE builtin documentation. - - Parameters - ---------- - tokens : (className, [fieldName]) - tuple containing one or two strings specifying class name - and field name (optional) to get documentation for. - - inherited: bool (default: False) - include inherited fields. - - Returns - ------- - docstring : str - Documentation string for class `className`.`fieldName` if both - are specified, for the class `className` if fieldName is not - specified. In the latter case, the fields and their data types - and finfo types are listed. - - Raises - ------ - NameError - If class or field does not exist. - - """ - indent = ' ' - with closing(StringIO()) as docstring: - if not tokens: - return "" - try: - class_element = _moose.element('/classes/%s' % (tokens[0])) - except ValueError: - raise NameError('name \'%s\' not defined.' % (tokens[0])) - if len(tokens) > 1: - docstring.write(toUnicode(getfielddoc(tokens))) - else: - docstring.write(toUnicode('%s\n' % (class_element.docs))) - append_finfodocs(tokens[0], docstring, indent) - if inherited: - mro = eval('_moose.%s' % (tokens[0])).mro() - for class_ in mro[1:]: - if class_ == _moose.melement: - break - docstring.write(toUnicode( - '\n\n#Inherited from %s#\n' % (class_.__name__))) - append_finfodocs(class_.__name__, docstring, indent) - if class_ == _moose.Neutral: # Neutral is the toplevel moose class - break - return docstring.getvalue() - - -def append_finfodocs(classname, docstring, indent): - """Append list of finfos in class name to docstring""" - try: - class_element = _moose.element('/classes/%s' % (classname)) - except ValueError: - raise NameError('class \'%s\' not defined.' % (classname)) - for ftype, rname in finfotypes: - docstring.write(toUnicode('\n*%s*\n' % (rname.capitalize()))) - try: - finfo = _moose.element('%s/%s' % (class_element.path, ftype)) - for field in finfo.vec: - docstring.write(toUnicode( - '%s%s: %s\n' % (indent, field.fieldName, field.type))) - except ValueError: - docstring.write(toUnicode('%sNone\n' % (indent))) - - -# the global pager is set from pydoc even if the user asks for paged -# help once. this is to strike a balance between GENESIS user's -# expectation of control returning to command line after printing the -# help and python user's expectation of seeing the help via more/less. -pager = None - - -def doc(arg, inherited=True, paged=True): - """Display the documentation for class or field in a class. - - Parameters - ---------- - arg : str/class/melement/vec - A string specifying a moose class name and a field name - separated by a dot. e.g., 'Neutral.name'. Prepending `moose.` - is allowed. Thus moose.doc('moose.Neutral.name') is equivalent - to the above. - It can also be string specifying just a moose class name or a - moose class or a moose object (instance of melement or vec - or there subclasses). In that case, the builtin documentation - for the corresponding moose class is displayed. - - paged: bool - Whether to display the docs via builtin pager or print and - exit. If not specified, it defaults to False and - moose.doc(xyz) will print help on xyz and return control to - command line. - - Returns - ------- - None - - Raises - ------ - NameError - If class or field does not exist. - - """ - # There is no way to dynamically access the MOOSE docs using - # pydoc. (using properties requires copying all the docs strings - # from MOOSE increasing the loading time by ~3x). Hence we provide a - # separate function. - global pager - if paged and pager is None: - pager = pydoc.pager - tokens = [] - text = '' - if isinstance(arg, str): - tokens = arg.split('.') - if tokens[0] == 'moose': - tokens = tokens[1:] - elif isinstance(arg, type): - tokens = [arg.__name__] - elif isinstance(arg, melement) or isinstance(arg, vec): - text = '%s: %s\n\n' % (arg.path, arg.className) - tokens = [arg.className] - if tokens: - text += getmoosedoc(tokens, inherited=inherited) - else: - text += pydoc.getdoc(arg) - if pager: - pager(text) - else: - print(text) - - -# -# moose.py ends here diff --git a/python/rdesigneur/rdesigneur.py b/python/rdesigneur/rdesigneur.py index e267921c..ed38fce9 100644 --- a/python/rdesigneur/rdesigneur.py +++ b/python/rdesigneur/rdesigneur.py @@ -454,6 +454,7 @@ class rdesigneur: "buildChemDistrib: No elec compartments found in path: '" \ + pair + "'" ) self.spineComptElist = self.elecid.spinesFromExpression[ pair ] + #print( 'LEN SPINECOMPTELIST =' + str( pair ) + ", " str( len( self.spineComptElist ) ) ) ''' if len( self.spineComptElist ) == 0: raise BuildError( \ @@ -1276,8 +1277,8 @@ class rdesigneur: else: ePath = i[0].path + '/' + elecRelPath if not( moose.exists( ePath ) ): - raise BuildError( \ - "Error: buildAdaptor: no elec obj in " + ePath ) + continue + #raise BuildError( "Error: buildAdaptor: no elec obj in " + ePath ) elObj = moose.element( i[0].path + '/' + elecRelPath ) if ( isElecToChem ): elecFieldSrc = 'get' + capField diff --git a/python/rdesigneur/rmoogli.py b/python/rdesigneur/rmoogli.py index 7f8fa883..c1b0d3aa 100644 --- a/python/rdesigneur/rmoogli.py +++ b/python/rdesigneur/rmoogli.py @@ -17,6 +17,7 @@ import os # Check if DISPLAY environment variable is properly set. If not, warn the user # and continue. hasDisplay = True +hasMoogli = False display = os.environ.get('DISPLAY', '' ) if not display: hasDisplay = False @@ -25,7 +26,6 @@ if not display: "Anyway, MOOSE will continue without graphics.\n" ) -hasMoogli = True if hasDisplay: try: @@ -33,11 +33,11 @@ if hasDisplay: import moogli import moogli.extensions.moose app = QtGui.QApplication(sys.argv) + hasMoogli = True except Exception as e: print( 'Warning: Moogli not found. All moogli calls will use dummy functions' ) hasMoogli = False - runtime = 0.0 moogliDt = 1.0 rotation = math.pi / 500.0 diff --git a/synapse/testSynapse.cpp b/synapse/testSynapse.cpp index db96a2aa..944525ff 100644 --- a/synapse/testSynapse.cpp +++ b/synapse/testSynapse.cpp @@ -129,14 +129,17 @@ void testRollingMatrix() cout << "." << flush; } +// FIXME: This test is failing on travis. void testSeqSynapse() { int numSyn = 10; int kernelWidth = 5; SeqSynHandler ssh; ssh.vSetNumSynapses( numSyn ); + // for ( int i = 0; i < numSyn; ++i ) // ssh.addSynapse(); + assert( static_cast< int >( ssh.vGetNumSynapses() ) == numSyn ); ssh.setSeqDt( 1.0 ); ssh.setHistoryTime( 5.0 ); @@ -155,11 +158,14 @@ void testSeqSynapse() cout << "." << flush; - ssh.setResponseScale( 1.0 ); + // FIXME: See issue BhallaLab/moose-core#174 + // ssh.setResponseScale( 1.0 ); for ( int i = 0; i < numSyn; ++i ) { ssh.addSpike( i, 0.0, 1.0 ); } - ssh.setWeightScale( 1.0 ); + + // FIXME: See issue BhallaLab/moose-core#174 + // ssh.setWeightScale( 1.0 ); ProcInfo p; Eref sheller( Id().eref() ); -- GitLab