From 5855deb683c0a9ce810d8405efb193c0739ee722 Mon Sep 17 00:00:00 2001 From: Dilawar Singh <dilawars@ncbs.res.in> Date: Sun, 10 Feb 2019 12:26:40 +0530 Subject: [PATCH] Squashed 'moose-core/' changes from e5868beb97..0f344909ae 0f344909ae SO_REUSEPORT is not always defined. The build fails on centos-5 (#351) 441a66ba82 Issue 342 | TCP/UD Socket based Table Streamer (#345) c67f8c0672 Travis build failure (#350) 053e256d76 Merge pull request #348 from analkumar2/master a165432ed2 Corrected the K_AHP z gate and make_Ca y gate c38c64380f Dec 19 | continuation of NML2 fixes (#344) e93d391be4 Hotfix: Neuroml2 fixes (#343) 1e426a2c16 Update INSTALL.md 2624d4b190 Continuation to PR #308 (#340) 0997a4623f Merge pull request #341 from hrani/master 4dfac333a3 using existing restoreXreacs function to remove _xfer_ objects before writting into SBML and genesis files ed7c4d58c3 Merge pull request #339 from upibhalla/master 1b48ce7ff7 Fix to CaConc to factor in valence of 2. Update to rdesigneur to handle SBML files 3aa66d4d34 Merge pull request #338 from hrani/master 356f43ce72 reading and writing diff and motor constant for pool d6e5711a27 Merge pull request #335 from hrani/master fac76ad723 groups and subgroups are written to sbml and read from xml files 69f9f33c38 Merge branch 'master' into master 169d0c88b2 Merge pull request #336 from upibhalla/master d57fa1de92 Merge branch 'master' of https://github.com/BhallaLab/moose-core b9a51133a3 Fix to Im calculation in HSolve, to include external channels like receptors. Also fix to Neuron.cpp for setting channelDistribution, to always load Ca_concs first, to ensure that any dependent channels are able to find them. 6868716b40 Merge branch 'master' into master 189778c8cd Merge pull request #331 from dilawar/master 7423c39e3b Merge branch 'master' into master 1a9b0f54df Merge branch 'master' into master 23906e50e5 searching for _xfer_ c40c622c0c xref pool are not wirtten and cleaned up if part of Reaction/Enzyme or notes, group are checked under all the mesh 01ebb8461e Merge pull request #333 from hrani/master d72ad63fc5 Merge branch 'master' of http://github.com/hrani/moose-core 0cd028c047 Added other meshes while searching for groups 2189993593 Merge branch 'master' into master 97913222e9 Reading and creating CylMesh and EndoMesh if specified in the Annotation field 4d1337ae68 Merge branch 'master' of github.com:dilawar/moose-core f6c4ab39cc Merge pull request #330 from hrani/master 26e966284f Tweaks. 90c97b6599 Fixed the bug caused by previous two commits. Now I need to make sure that ca pool is read at each timepoint. 86522d326e Using built in logging library. b327ec7d39 xfer cross compartment molecules are not written as species and also for Reaction and Enzyme e5fbf8c5db For CylMesh, totLength and diffLength is written to Annotation to get number of voxel d569f56a39 gate with id z is loaded into gateZ in moose now. b38a4405ae Squashed commit of the following: ef8e54a15b variable name used in before assignment cleanup 740a7a65b9 CylMesh,EndoMesh,NeuroMesh compartment are written to SBML as compartment with annotation field in which surround,isMembraneBound,numDiffCompts git-subtree-dir: moose-core git-subtree-split: 0f344909ae285b147b4bc61089b8ee52aa6b9186 --- .travis.yml | 5 +- .travis/travis_prepare_osx.sh | 6 +- CMakeLists.txt | 8 +- INSTALL.md | 101 +- basecode/ObjId.cpp | 102 +- basecode/ObjId.h | 185 +-- basecode/SetGet.h | 1610 +++++++++++---------- biophysics/CaConcBase.cpp | 6 +- biophysics/HHGate.cpp | 1254 ++++++++-------- biophysics/HHGate.h | 7 +- biophysics/Neuron.cpp | 21 +- builtins/CMakeLists.txt | 1 + builtins/SocketStreamer.cpp | 591 ++++++++ builtins/SocketStreamer.h | 164 +++ builtins/Streamer.cpp | 2 +- builtins/StreamerBase.cpp | 8 +- builtins/StreamerBase.h | 11 + builtins/Table.cpp | 131 +- builtins/Table.h | 21 +- builtins/TableBase.cpp | 698 ++++----- builtins/TableBase.h | 4 +- hsolve/HSolveActive.cpp | 1 + hsolve/HSolveActive.h | 1 + hsolve/HSolveActiveSetup.cpp | 1 + hsolve/HSolveInterface.cpp | 2 + ksolve/testKsolve.cpp | 552 +++---- pymoose/moosemodule.cpp | 91 +- pymoose/moosemodule.h | 2 +- python/moose/SBML/readSBML.py | 177 ++- python/moose/SBML/writeSBML.py | 316 ++-- python/moose/__init__.py | 11 +- python/moose/chemMerge/merge.py | 42 +- python/moose/chemUtil/chemConnectUtil.py | 4 +- python/moose/genesis/writeKkit.py | 38 +- python/moose/moose.py | 185 +-- python/moose/neuroml2/reader.py | 286 ++-- python/moose/neuroml2/units.py | 55 +- python/moose/server.py | 320 ++++ python/rdesigneur/rdesigneur.py | 7 +- python/rdesigneur/rdesigneurProtos.py | 5 +- scheduling/Clock.cpp | 359 ++--- scripts/Makefile.wheel | 18 - scripts/Portfile | 56 - scripts/build-moose-core | 11 - scripts/build_debian.sh | 36 - scripts/build_debian_locally_on_ubuntu.sh | 5 - scripts/build_debian_using_bzr.sh | 36 - scripts/build_macosx_bundle.sh | 12 - scripts/build_pypi.sh | 20 - scripts/build_using_gcc_on_mac.sh | 11 - scripts/cmake_sanity_check.py | 98 -- scripts/color.sh | 48 - scripts/moose | 3 - scripts/moose.desktop | 8 - scripts/moosegui | 3 - scripts/moosegui.py | 28 - scripts/postinst | 40 - scripts/prerm | 72 - scripts/submit.py | 147 ++ shell/Shell.cpp | 95 +- shell/Shell.h | 37 +- shell/Wildcard.cpp | 5 +- shell/Wildcard.h | 4 +- tests/python/models.py | 26 + tests/python/test_moose_attribs.py | 4 +- tests/python/test_socket_streamer_tcp.py | 182 +++ tests/python/test_socket_streamer_uds.py | 128 ++ utility/setupenv.cpp | 18 + utility/strutil.cpp | 2 + utility/strutil.h | 31 +- utility/utility.h | 3 + 71 files changed, 5048 insertions(+), 3530 deletions(-) create mode 100644 builtins/SocketStreamer.cpp create mode 100644 builtins/SocketStreamer.h create mode 100644 python/moose/server.py delete mode 100644 scripts/Makefile.wheel delete mode 100644 scripts/Portfile delete mode 100755 scripts/build-moose-core delete mode 100755 scripts/build_debian.sh delete mode 100755 scripts/build_debian_locally_on_ubuntu.sh delete mode 100755 scripts/build_debian_using_bzr.sh delete mode 100755 scripts/build_macosx_bundle.sh delete mode 100755 scripts/build_pypi.sh delete mode 100755 scripts/build_using_gcc_on_mac.sh delete mode 100755 scripts/cmake_sanity_check.py delete mode 100755 scripts/color.sh delete mode 100755 scripts/moose delete mode 100644 scripts/moose.desktop delete mode 100755 scripts/moosegui delete mode 100755 scripts/moosegui.py delete mode 100755 scripts/postinst delete mode 100755 scripts/prerm create mode 100755 scripts/submit.py create mode 100644 tests/python/models.py create mode 100644 tests/python/test_socket_streamer_tcp.py create mode 100644 tests/python/test_socket_streamer_uds.py diff --git a/.travis.yml b/.travis.yml index e6912225..c4aa5e91 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,10 @@ os: - linux - osx -osx_image: xcode10 +matrix: + include: + - os : osx + osx_image: xcode10 notifications: email: diff --git a/.travis/travis_prepare_osx.sh b/.travis/travis_prepare_osx.sh index d8aa29a1..d56638ed 100755 --- a/.travis/travis_prepare_osx.sh +++ b/.travis/travis_prepare_osx.sh @@ -20,9 +20,9 @@ set -o nounset # Treat unset variables as an error set +e #rvm get head -#brew update -#brew outdated cmake || brew install cmake -brew install gsl +brew update || echo "failed to update" +brew outdated cmake || brew install cmake +brew install gsl || brew upgrade gsl brew install hdf5 brew install python brew install numpy diff --git a/CMakeLists.txt b/CMakeLists.txt index ec094e58..b30ca55d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,7 +97,7 @@ else() message(STATUS "Building for Release/No unit tests.") set(CMAKE_BUILD_TYPE Release) add_definitions(-UDO_UNIT_TESTS -O3 -DDISABLE_DEBUG) - + # DO NOT Treat all warnings as errors. With some compilers and newer versions # this often causes headache. # add_definitions(-Werror) @@ -353,7 +353,7 @@ if(SYSTEM_SHARED_LIBS) list(REMOVE_DUPLICATES SYSTEM_SHARED_LIBS) endif( ) -# cmake --help-policy CMP0042. Also in pymoose/CMakeLists.txt +# cmake --help-policy CMP0042. Also in pymoose/CMakeLists.txt # More details: # https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/RPATH-handling # especially section 'Mac OS X and the RPATH' @@ -528,8 +528,8 @@ foreach( _py_script ${PY_SCRIPTS} ) file( READ ${_py_script} pytext) string(MD5 _md5 "${pytext}") set(TGT_NAME "${_py_name}-${_md5}" ) - set(PYLINT_OPTIONS --disable=no-member --disable=no-name-in-module - --disable=invalid-unary-operand-type + set(PYLINT_OPTIONS --disable=no-member --disable=no-name-in-module + --disable=invalid-unary-operand-type --disable=import-error --disable=no-method-argument ) diff --git a/INSTALL.md b/INSTALL.md index 6f2272b2..63af4f3a 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,43 +1,22 @@ -# Pre-built packages - -## Linux - -Use our repositories hosted at [Open Build Service](http://build.opensuse.org). -We have packages for Debian, Ubuntu, CentOS, Fedora, OpenSUSE/SUSE, RHEL, -Scientific Linux. Visit the following page for instructions. - -https://software.opensuse.org/download.html?project=home:moose&package=moose - -## MacOSX - -MOOSE is available via [homebrew](http://brew.sh). - - $ brew install homebrew/science/moose - - # Building MOOSE from source -To build `MOOSE` from source, you can either use `cmake` (recommended) or GNU `make` based flow. +To build `MOOSE` from source, you need `cmake`. Download the latest source code of moose from github. - $ git clone -b master https://github.com/BhallaLab/moose-core + $ git clone -b master https://github.com/BhallaLab/moose-core --depth 50 ## Install dependencies -For moose-core: - - gsl-1.16 or higher. - libhdf5-dev (optional) - python-dev - python-numpy -On Ubuntu-12.04 or higher, these can be installed with: +On Ubuntu-14.04 or higher, these can be installed with: sudo apt-get install python-dev python-numpy libhdf5-dev cmake libgsl0-dev g++ -__NOTE__ : On Ubuntu 12.04, gsl version is 1.15. You should skip `libgsl0-dev` install gsl-1.16 or higher manually. - SBML support is enabled by installing [python-libsbml](http://sbml.org/Software/libSBML/docs/python-api/libsbml-installation.html). Alternatively, it can be installed by using `python-pip` $ sudo pip install python-libsbml @@ -48,90 +27,24 @@ SBML support is enabled by installing [python-libsbml](http://sbml.org/Software/ $ mkdir _build $ cd _build $ cmake .. - $ make - $ ctest --output-on-failure + $ make -j3 + $ ctest -j3 --output-on-failure -This will build moose and its python extentions, `ctest` will run few tests to -check if build process was successful. +This will build moose, `ctest` will run few tests to check if build process was successful. To install MOOSE into non-standard directory, pass additional argument `-DCMAKE_INSTALL_PREFIX=path/to/install/dir` to cmake. ### Python3 -You just need to one command in previous set of instructions to following - cmake -DPYTHON_EXECUTABLE=/opt/bin/python3 .. ### Install $ sudo make install -## Using gnu-make - -__This may or may not work (not maintained by packager)__ - -You may need to inform make of C++ include directories and library directories -if your installed packages are at non-standard location. For example, if your -have libsbml installed in `/opt/libsbml` and the header files are located in -`/opt/libsbml/include` and lib files are located in `/opt/libsbml/lib`, you can -set the environment variables `CXXFLAGS` and `LDFLAGS` to include these before -calling make: - - export CXXFLAGS= -I/opt/libsbml/include - export LDFLAGS= -L/opt/libsbml/lib - - -### Release build: - - cd moose - make BUILD=release - -### Debug build: - - cd moose - make BUILD=debug - -### Python 3K - -By default, MOOSE is built for Python 2. In case you want to build MOOSE for -Python 3K, you need to pass the additional flag: - - PYTHON=3 - -like: - - make BUILD=release PYTHON=3 - -## Installation: - -For system-wide installation you can run: - - sudo make install - ## Post installation Now you can import moose in a Python script or interpreter with the statement: import moose - -If you have installed the GUI dependencies below for running the graphical user -interface, then you can run the GUI by double-clicking on the desktop icon or -via the main-menu. The squid axon tutorial/demo is also accessible via these -routes. - -## Local-installation - -If you do not have permission to install it in system directories, you can let -it be where it was built or copy the `python` subdirectory of MOOSE source tree -to a location of your choice and add the path to your PYTHONPATH environment -variable. Suppose you have a ~/lib directory where you keep all your locally -built libraries, do: - - cp -r {moose-source-directory}/python ~/lib/ - -and add this to your .bashrc file (if you use bash shell): - - export PYTHONPATH="$HOME/lib/python":"$PYTHONPATH" - -For other shells, look up your shell's manual to find out how to set environment -variable in it. + moose.test() # will take time. Not all tests will pass. diff --git a/basecode/ObjId.cpp b/basecode/ObjId.cpp index 9e846603..9c1c8231 100644 --- a/basecode/ObjId.cpp +++ b/basecode/ObjId.cpp @@ -17,33 +17,33 @@ // Doesn't know how to deal with off-node bad fields. bool ObjId::bad() const { - Element* elm = id.element(); - return ( elm == 0 || - dataIndex == BADINDEX || - fieldIndex == BADINDEX || - dataIndex >= elm->numData() - /* - * We have a bit of a problem here. The FieldElement can exist - * with zero fields, and is invalid for field lookups but valid - * for the element level lookups. I should rather not create the - * FieldElements this way. - || ( - elm->getNode( dataIndex ) == Shell::myNode() && - fieldIndex >= elm->numField( dataIndex - elm->localDataStart() ) - ) - */ - ); + Element* elm = id.element(); + return ( elm == 0 || + dataIndex == BADINDEX || + fieldIndex == BADINDEX || + dataIndex >= elm->numData() + /* + * We have a bit of a problem here. The FieldElement can exist + * with zero fields, and is invalid for field lookups but valid + * for the element level lookups. I should rather not create the + * FieldElements this way. + || ( + elm->getNode( dataIndex ) == Shell::myNode() && + fieldIndex >= elm->numField( dataIndex - elm->localDataStart() ) + ) + */ + ); } ostream& operator <<( ostream& s, const ObjId& i ) { - if ( i.dataIndex == 0 && i.fieldIndex == 0 ) - s << i.id; - else if ( i.fieldIndex == 0 ) - s << i.id << "[" << i.dataIndex << "]"; - else - s << i.id << "[" << i.dataIndex << "][" << i.fieldIndex << "]"; - return s; + if ( i.dataIndex == 0 && i.fieldIndex == 0 ) + s << i.id; + else if ( i.fieldIndex == 0 ) + s << i.id << "[" << i.dataIndex << "]"; + else + s << i.id << "[" << i.dataIndex << "][" << i.fieldIndex << "]"; + return s; } /** @@ -51,77 +51,77 @@ ostream& operator <<( ostream& s, const ObjId& i ) */ istream& operator >>( istream& s, ObjId& i ) { - s >> i.id; - return s; + s >> i.id; + return s; } ////////////////////////////////////////////////////////////// ObjId::ObjId( const string& path ) { - Shell* shell = reinterpret_cast< Shell* >( Id().eref().data() ); - assert( shell ); - *this = shell->doFind( path ); + Shell* shell = reinterpret_cast< Shell* >( Id().eref().data() ); + assert( shell ); + *this = shell->doFind( path ); } Eref ObjId::eref() const { - return Eref( id.element(), dataIndex, fieldIndex ); + return Eref( id.element(), dataIndex, fieldIndex ); } bool ObjId::operator==( const ObjId& other ) const { - return ( id == other.id && dataIndex == other.dataIndex && - fieldIndex == other.fieldIndex ); + return ( id == other.id && dataIndex == other.dataIndex && + fieldIndex == other.fieldIndex ); } bool ObjId::operator!=( const ObjId& other ) const { - return ( id != other.id || dataIndex != other.dataIndex || - fieldIndex != other.fieldIndex ); + return ( id != other.id || dataIndex != other.dataIndex || + fieldIndex != other.fieldIndex ); } bool ObjId::operator<( const ObjId& other ) const { - return ( id < other.id || - (id == other.id && ( - dataIndex < other.dataIndex || - ( dataIndex == other.dataIndex && - fieldIndex < other.fieldIndex ) - ) - ) - ); + return ( id < other.id || + (id == other.id && ( + dataIndex < other.dataIndex || + ( dataIndex == other.dataIndex && + fieldIndex < other.fieldIndex ) + ) + ) + ); } bool ObjId::isDataHere() const { - return ( id.element()->getNode( dataIndex ) == Shell::myNode() ); + return ( id.element()->getNode( dataIndex ) == Shell::myNode() ); } bool ObjId::isGlobal() const { - return ( id.element()->isGlobal() ); + return ( id.element()->isGlobal() ); } bool ObjId::isOffNode() const { - return ( Shell::numNodes() > 1 && - ( id.element()->isGlobal() || - id.element()->getNode( dataIndex ) != Shell::myNode() ) - ); + return ( Shell::numNodes() > 1 && + ( id.element()->isGlobal() || + id.element()->getNode( dataIndex ) != Shell::myNode() ) + ); } char* ObjId::data() const { - return id.element()->data( id.element()->rawIndex( dataIndex ), - fieldIndex ); + return id.element()->data( id.element()->rawIndex( dataIndex ), + fieldIndex ); } string ObjId::path() const { - return Neutral::path( eref() ); + return Neutral::path( eref() ); } Element* ObjId::element() const { - return id.element(); + return id.element(); } diff --git a/basecode/ObjId.h b/basecode/ObjId.h index 9f279f45..ab91204c 100644 --- a/basecode/ObjId.h +++ b/basecode/ObjId.h @@ -19,95 +19,102 @@ */ class ObjId { - friend ostream& operator <<( ostream& s, const ObjId& i ); - friend istream& operator >>( istream& s, ObjId& i ); - public: - ////////////////////////////////////////////////////////////// - // ObjId creation - ////////////////////////////////////////////////////////////// - /** - * Returns the root Id - */ - ObjId() - : id(), dataIndex( 0 ), fieldIndex( 0 ) - {;} - - /** - * Creates a ObjId using specified Id and DataIndex - */ - ObjId( Id i, unsigned int d, unsigned int f = 0 ) - : id( i ), dataIndex( d ), fieldIndex( f ) - {;} - - ObjId( Id i ) - : id( i ), dataIndex( 0 ), fieldIndex( 0 ) - {;} - - /** - * Creates an ObjId by reading the path string - * Returns bad on failure. - */ - ObjId( const string& path ); - - /** - * Returns the absolute path including all array indices. - */ - string path() const; - - /** - * Returns the Eref matching itself. - */ - Eref eref() const; - - /** - * For equality check - */ - bool operator==( const ObjId& other ) const; - bool operator!=( const ObjId& other ) const; - - /** - * For sorting - */ - bool operator<( const ObjId& other ) const; - - /** - * True if the data is present on the current node. Always true for - * globals, which confuses the matter somewhat. - */ - bool isDataHere() const; - - /// Returns true if the Element is global. - bool isGlobal() const; - - /// Returns true if we need to go off-node for calling operations - bool isOffNode() const; - - /** - * Returns data entry for this object - */ - char* data() const; - - /** - * Returns Element part - */ - Element* element() const; - - /** - * Here are the data values. - */ - Id id; - unsigned int dataIndex; - unsigned int fieldIndex; - - /** - * True if the return value is bad: either returning a failure, - * or the DataIndex or FieldIndex is out of range. However, this - * is a node-local funtion so it can't report the FieldIndex status - * in all cases. - */ - bool bad() const; - - private: + friend ostream& operator <<( ostream& s, const ObjId& i ); + friend istream& operator >>( istream& s, ObjId& i ); + +public: + ////////////////////////////////////////////////////////////// + // ObjId creation + ////////////////////////////////////////////////////////////// + /** + * Returns the root Id + */ + ObjId() + : id(), dataIndex( 0 ), fieldIndex( 0 ) + { + ; + } + + /** + * Creates a ObjId using specified Id and DataIndex + */ + ObjId( Id i, unsigned int d, unsigned int f = 0 ) + : id( i ), dataIndex( d ), fieldIndex( f ) + { + ; + } + + ObjId( Id i ) + : id( i ), dataIndex( 0 ), fieldIndex( 0 ) + { + ; + } + + /** + * Creates an ObjId by reading the path string + * Returns bad on failure. + */ + ObjId( const string& path ); + + /** + * Returns the absolute path including all array indices. + */ + string path() const; + + /** + * Returns the Eref matching itself. + */ + Eref eref() const; + + /** + * For equality check + */ + bool operator==( const ObjId& other ) const; + bool operator!=( const ObjId& other ) const; + + /** + * For sorting + */ + bool operator<( const ObjId& other ) const; + + /** + * True if the data is present on the current node. Always true for + * globals, which confuses the matter somewhat. + */ + bool isDataHere() const; + + /// Returns true if the Element is global. + bool isGlobal() const; + + /// Returns true if we need to go off-node for calling operations + bool isOffNode() const; + + /** + * Returns data entry for this object + */ + char* data() const; + + /** + * Returns Element part + */ + Element* element() const; + + /** + * Here are the data values. + */ + Id id; + unsigned int dataIndex; + unsigned int fieldIndex; + + /** + * True if the return value is bad: either returning a failure, + * or the DataIndex or FieldIndex is out of range. However, this + * is a node-local funtion so it can't report the FieldIndex status + * in all cases. + */ + bool bad() const; + +private: }; #endif // _OBJ_ID_H diff --git a/basecode/SetGet.h b/basecode/SetGet.h index fc855b20..1788d6ad 100644 --- a/basecode/SetGet.h +++ b/basecode/SetGet.h @@ -29,325 +29,350 @@ template< class T, class A > class GetOpFunc; template< class T, class A > A localGet( const Eref& er, string field ) { - string fullFieldName = "get" + field; - fullFieldName[3] = std::toupper( fullFieldName[3] ); - const Finfo* finfo = er.element()->cinfo()->findFinfo( fullFieldName ); - assert( finfo ); + string fullFieldName = "get" + field; + fullFieldName[3] = std::toupper( fullFieldName[3] ); + const Finfo* finfo = er.element()->cinfo()->findFinfo( fullFieldName ); + assert( finfo ); - const DestFinfo* dest = dynamic_cast< const DestFinfo* >( finfo ); - assert( dest ); + const DestFinfo* dest = dynamic_cast< const DestFinfo* >( finfo ); + assert( dest ); - const OpFunc* op = dest->getOpFunc(); - assert( op ); + const OpFunc* op = dest->getOpFunc(); + assert( op ); - const GetOpFunc< T, A >* gop = - dynamic_cast< const GetOpFunc< T, A >* >( op ); - assert( gop ); + const GetOpFunc< T, A >* gop = + dynamic_cast< const GetOpFunc< T, A >* >( op ); + assert( gop ); - return gop->reduceOp( er ); + return gop->reduceOp( er ); } class SetGet { - public: - SetGet() - {;} - - virtual ~SetGet() - {;} - - /** - * Utility function to check that the target field matches this - * source type, to look up and pass back the fid, and to return - * the number of targetEntries. - * Tgt is passed in as the destination ObjId. May be changed inside, - * if the function determines that it should be directed to a - * child Element acting as a Value. - * Checks arg # and types for a 'set' call. Can be zero to 3 args. - * Returns # of tgts if good. This is 0 if bad. - * Passes back found fid. - */ - static const OpFunc* checkSet( - const string& field, ObjId& tgt, FuncId& fid ); +public: + SetGet() + { + ; + } + + virtual ~SetGet() + { + ; + } + + /** + * Utility function to check that the target field matches this + * source type, to look up and pass back the fid, and to return + * the number of targetEntries. + * Tgt is passed in as the destination ObjId. May be changed inside, + * if the function determines that it should be directed to a + * child Element acting as a Value. + * Checks arg # and types for a 'set' call. Can be zero to 3 args. + * Returns # of tgts if good. This is 0 if bad. + * Passes back found fid. + */ + static const OpFunc* checkSet( + const string& field, ObjId& tgt, FuncId& fid ); ////////////////////////////////////////////////////////////////////// - /** - * Blocking 'get' call, returning into a string. - * There is a matching 'get<T> call, returning appropriate type. - */ - static bool strGet( const ObjId& tgt, const string& field, string& ret ); - - /** - * Blocking 'set' call, using automatic string conversion - * There is a matching blocking set call with typed arguments. - */ - static bool strSet( const ObjId& dest, const string& field, const string& val ); - - /// Sends out request for data, and awaits its return. - static const vector< double* >* dispatchGet( - const ObjId& tgt, FuncId tgtFid, - const double* arg, unsigned int size ); - - virtual bool checkOpClass( const OpFunc* op ) const = 0; + /** + * Blocking 'get' call, returning into a string. + * There is a matching 'get<T> call, returning appropriate type. + */ + static bool strGet( const ObjId& tgt, const string& field, string& ret ); + + /** + * Blocking 'set' call, using automatic string conversion + * There is a matching blocking set call with typed arguments. + */ + static bool strSet( const ObjId& dest, const string& field, const string& val ); + + /// Sends out request for data, and awaits its return. + static const vector< double* >* dispatchGet( + const ObjId& tgt, FuncId tgtFid, + const double* arg, unsigned int size ); + + virtual bool checkOpClass( const OpFunc* op ) const = 0; }; class SetGet0: public SetGet { - public: - SetGet0() - {;} - - /** - * Blocking, typed 'Set' call - */ - static bool set( const ObjId& dest, const string& field ) - { - FuncId fid; - ObjId tgt( dest ); // checkSet may change the tgt. - const OpFunc* func = checkSet( field, tgt, fid ); - const OpFunc0Base* op = - dynamic_cast< const OpFunc0Base* >( func ); - if ( op ) { - if ( tgt.isOffNode() ) { - const OpFunc* op2 = op->makeHopFunc( - HopIndex( op->opIndex(), MooseSetHop ) ); - const OpFunc0Base* hop = - dynamic_cast< const OpFunc0Base* >( op2 ); - assert( hop ); - hop->op( tgt.eref() ); - delete op2; - if ( tgt.isGlobal() ) - op->op( tgt.eref() ); - return true; - } else { - op->op( tgt.eref() ); - return true; - } - } - return 0; - } - - /** - * Blocking call using string conversion - */ - static bool innerStrSet( const ObjId& dest, const string& field, - const string& val ) - { - return set( dest, field ); - } - - bool checkOpClass( const OpFunc* op ) const { - return dynamic_cast< const OpFunc0Base* >( op ); - } +public: + SetGet0() + { + ; + } + + /** + * Blocking, typed 'Set' call + */ + static bool set( const ObjId& dest, const string& field ) + { + FuncId fid; + ObjId tgt( dest ); // checkSet may change the tgt. + const OpFunc* func = checkSet( field, tgt, fid ); + const OpFunc0Base* op = + dynamic_cast< const OpFunc0Base* >( func ); + if ( op ) + { + if ( tgt.isOffNode() ) + { + const OpFunc* op2 = op->makeHopFunc( + HopIndex( op->opIndex(), MooseSetHop ) ); + const OpFunc0Base* hop = + dynamic_cast< const OpFunc0Base* >( op2 ); + assert( hop ); + hop->op( tgt.eref() ); + delete op2; + if ( tgt.isGlobal() ) + op->op( tgt.eref() ); + return true; + } + else + { + op->op( tgt.eref() ); + return true; + } + } + return 0; + } + + /** + * Blocking call using string conversion + */ + static bool innerStrSet( const ObjId& dest, const string& field, + const string& val ) + { + return set( dest, field ); + } + + bool checkOpClass( const OpFunc* op ) const + { + return dynamic_cast< const OpFunc0Base* >( op ); + } }; template< class A > class SetGet1: public SetGet { - public: - SetGet1() - {;} - - /** - * Blocking, typed 'Set' call - */ - static bool set( const ObjId& dest, const string& field, A arg ) - { - FuncId fid; - ObjId tgt( dest ); - const OpFunc* func = checkSet( field, tgt, fid ); - const OpFunc1Base< A >* op = - dynamic_cast< const OpFunc1Base< A >* >( func ); - if ( op ) { - if ( tgt.isOffNode() ) { - const OpFunc* op2 = op->makeHopFunc( - HopIndex( op->opIndex(), MooseSetHop ) ); - const OpFunc1Base< A >* hop = - dynamic_cast< const OpFunc1Base< A >* >( op2 ); - hop->op( tgt.eref(), arg ); - delete op2; - if ( tgt.isGlobal() ) - op->op( tgt.eref(), arg ); - return true; - } else { - op->op( tgt.eref(), arg ); - return true; - } - } - return false; - } - - /** - * setVec assigns all the entries in the target Id to the - * specified vector of values. If the target is a FieldElement - * it assigns the entries on the specific DataIndex provided in the - * ObjId argument. - * The vector is used as a circular - * buffer: if the number of targets exceeds the vector size, it - * rolls over. - */ - static bool setVec( ObjId destId, const string& field, - const vector< A >& arg ) - { - if ( arg.size() == 0 ) return 0; - - ObjId tgt( destId ); - FuncId fid; - - const OpFunc* func = checkSet( field, tgt, fid ); - const OpFunc1Base< A >* op = dynamic_cast< const OpFunc1Base< A >* >( func ); - if ( op ) { - const OpFunc* op2 = op->makeHopFunc( - HopIndex( op->opIndex(), MooseSetVecHop ) ); - const OpFunc1Base< A >* hop = - dynamic_cast< const OpFunc1Base< A >* >( op2 ); - hop->opVec( tgt.eref(), arg, op ); - delete op2; - return true; - } - return false; - } - - /** - * Sets all target array values to the single value - */ - static bool setRepeat( ObjId destId, const string& field, - const A& arg ) - { - vector< A >temp ( 1, arg ); - return setVec( destId, field, temp ); - } - - /** - * Blocking call using string conversion - */ - static bool innerStrSet( const ObjId& dest, const string& field, - const string& val ) - { - A arg; - Conv< A >::str2val( arg, val ); - return set( dest, field, arg ); - } - - bool checkOpClass( const OpFunc* op ) const { - return dynamic_cast< const OpFunc1Base< A > * >( op ); - } +public: + SetGet1() + { + ; + } + + /** + * Blocking, typed 'Set' call + */ + static bool set( const ObjId& dest, const string& field, A arg ) + { + FuncId fid; + ObjId tgt( dest ); + const OpFunc* func = checkSet( field, tgt, fid ); + const OpFunc1Base< A >* op = dynamic_cast< const OpFunc1Base< A >* >( func ); + if ( op ) + { + if ( tgt.isOffNode() ) + { + const OpFunc* op2 = op->makeHopFunc( + HopIndex( op->opIndex(), MooseSetHop ) ); + const OpFunc1Base< A >* hop = + dynamic_cast< const OpFunc1Base< A >* >( op2 ); + hop->op( tgt.eref(), arg ); + delete op2; + if ( tgt.isGlobal() ) + op->op( tgt.eref(), arg ); + return true; + } + else + { + op->op( tgt.eref(), arg ); + return true; + } + } + return false; + } + + /** + * setVec assigns all the entries in the target Id to the + * specified vector of values. If the target is a FieldElement + * it assigns the entries on the specific DataIndex provided in the + * ObjId argument. + * The vector is used as a circular + * buffer: if the number of targets exceeds the vector size, it + * rolls over. + */ + static bool setVec( ObjId destId, const string& field, + const vector< A >& arg ) + { + if ( arg.size() == 0 ) return 0; + + ObjId tgt( destId ); + FuncId fid; + + const OpFunc* func = checkSet( field, tgt, fid ); + const OpFunc1Base< A >* op = dynamic_cast< const OpFunc1Base< A >* >( func ); + if ( op ) + { + const OpFunc* op2 = op->makeHopFunc( + HopIndex( op->opIndex(), MooseSetVecHop ) ); + const OpFunc1Base< A >* hop = + dynamic_cast< const OpFunc1Base< A >* >( op2 ); + hop->opVec( tgt.eref(), arg, op ); + delete op2; + return true; + } + return false; + } + + /** + * Sets all target array values to the single value + */ + static bool setRepeat( ObjId destId, const string& field, + const A& arg ) + { + vector< A >temp ( 1, arg ); + return setVec( destId, field, temp ); + } + + /** + * Blocking call using string conversion + */ + static bool innerStrSet( const ObjId& dest, const string& field, + const string& val ) + { + A arg; + Conv< A >::str2val( arg, val ); + return set( dest, field, arg ); + } + + bool checkOpClass( const OpFunc* op ) const + { + return dynamic_cast< const OpFunc1Base< A > * >( op ); + } }; template< class A > class Field: public SetGet1< A > { - public: - Field() - {;} - - /** - * Blocking, typed 'Set' call - */ - static bool set( const ObjId& dest, const string& field, A arg ) - { - string temp = "set" + field; - temp[3] = std::toupper( temp[3] ); - return SetGet1< A >::set( dest, temp, arg ); - } - - static bool setVec( ObjId destId, const string& field, - const vector< A >& arg ) - { - string temp = "set" + field; - temp[3] = std::toupper( temp[3] ); - return SetGet1< A >::setVec( destId, temp, arg ); - } - - static bool setRepeat( ObjId destId, const string& field, - A arg ) - { - string temp = "set" + field; - temp[3] = std::toupper( temp[3] ); - return SetGet1< A >::setRepeat( destId, temp, arg ); - } - - /** - * Blocking call using string conversion - */ - static bool innerStrSet( const ObjId& dest, const string& field, - const string& arg ) - { - A val; - // Do NOT add 'set_' to the field name, as the 'set' func - // does it anyway. - Conv< A >::str2val( val, arg ); - return set( dest, field, val ); - } - - ////////////////////////////////////////////////////////////////// - - // Returns a field value. - static A get( const ObjId& dest, const string& field) - { - ObjId tgt( dest ); - FuncId fid; - string fullFieldName = "get" + field; - fullFieldName[3] = std::toupper( fullFieldName[3] ); - const OpFunc* func = SetGet::checkSet( fullFieldName, tgt, fid ); - const GetOpFuncBase< A >* gof = - dynamic_cast< const GetOpFuncBase< A >* >( func ); - if ( gof ) { - if ( tgt.isDataHere() ) { - return gof->returnOp( tgt.eref() ); - } else { - const OpFunc* op2 = gof->makeHopFunc( - HopIndex( gof->opIndex(), MooseGetHop ) ); - const OpFunc1Base< A* >* hop = - dynamic_cast< const OpFunc1Base< A* >* >( op2 ); - assert( hop ); - // Blocking function. - A ret; - hop->op( tgt.eref(), &ret ); - delete op2; - return ret; - } - } - cout << "Warning: Field::Get conversion error for " << - dest.id.path() << "." << field << endl; - return A(); - } - - /** - * Returns a vector of values - */ - static void getVec( ObjId dest, const string& field, vector< A >& vec) - { - - vec.resize( 0 ); - ObjId tgt( dest ); - FuncId fid; - string fullFieldName = "get" + field; - fullFieldName[3] = std::toupper( fullFieldName[3] ); - const OpFunc* func = SetGet::checkSet( fullFieldName, tgt, fid ); - const GetOpFuncBase< A >* gof = - dynamic_cast< const GetOpFuncBase< A >* >( func ); - if ( gof ) { - const OpFunc* op2 = gof->makeHopFunc( - HopIndex( gof->opIndex(), MooseGetVecHop ) ); - const GetHopFunc< A >* hop = - dynamic_cast< const GetHopFunc< A >* >( op2 ); - hop->opGetVec( tgt.eref(), vec, gof ); - delete op2; - return; - } - cout << "Warning: Field::getVec conversion error for " << - dest.path() << endl; - } - - /** - * Blocking call for finding a value and returning in a - * string. - */ - static bool innerStrGet( const ObjId& dest, const string& field, - string& str ) - { - Conv< A >::val2str( str, get( dest, field ) ); - return 1; - } +public: + Field() + { + ; + } + + /** + * Blocking, typed 'Set' call + */ + static bool set( const ObjId& dest, const string& field, A arg ) + { + string temp = "set" + field; + temp[3] = std::toupper( temp[3] ); + return SetGet1< A >::set( dest, temp, arg ); + } + + static bool setVec( ObjId destId, const string& field, + const vector< A >& arg ) + { + string temp = "set" + field; + temp[3] = std::toupper( temp[3] ); + return SetGet1< A >::setVec( destId, temp, arg ); + } + + static bool setRepeat( ObjId destId, const string& field, + A arg ) + { + string temp = "set" + field; + temp[3] = std::toupper( temp[3] ); + return SetGet1< A >::setRepeat( destId, temp, arg ); + } + + /** + * Blocking call using string conversion + */ + static bool innerStrSet( const ObjId& dest, const string& field, + const string& arg ) + { + A val; + // Do NOT add 'set_' to the field name, as the 'set' func + // does it anyway. + Conv< A >::str2val( val, arg ); + return set( dest, field, val ); + } + + ////////////////////////////////////////////////////////////////// + + // Returns a field value. + static A get( const ObjId& dest, const string& field) + { + ObjId tgt( dest ); + FuncId fid; + string fullFieldName = "get" + field; + fullFieldName[3] = std::toupper( fullFieldName[3] ); + const OpFunc* func = SetGet::checkSet( fullFieldName, tgt, fid ); + const GetOpFuncBase< A >* gof = + dynamic_cast< const GetOpFuncBase< A >* >( func ); + if ( gof ) + { + if ( tgt.isDataHere() ) + { + return gof->returnOp( tgt.eref() ); + } + else + { + const OpFunc* op2 = gof->makeHopFunc( + HopIndex( gof->opIndex(), MooseGetHop ) ); + const OpFunc1Base< A* >* hop = + dynamic_cast< const OpFunc1Base< A* >* >( op2 ); + assert( hop ); + // Blocking function. + A ret; + hop->op( tgt.eref(), &ret ); + delete op2; + return ret; + } + } + cout << "Warning: Field::Get conversion error for " << + dest.id.path() << "." << field << endl; + return A(); + } + + /** + * Returns a vector of values + */ + static void getVec( ObjId dest, const string& field, vector< A >& vec) + { + + vec.resize( 0 ); + ObjId tgt( dest ); + FuncId fid; + string fullFieldName = "get" + field; + fullFieldName[3] = std::toupper( fullFieldName[3] ); + const OpFunc* func = SetGet::checkSet( fullFieldName, tgt, fid ); + const GetOpFuncBase< A >* gof = + dynamic_cast< const GetOpFuncBase< A >* >( func ); + if ( gof ) + { + const OpFunc* op2 = gof->makeHopFunc( + HopIndex( gof->opIndex(), MooseGetVecHop ) ); + const GetHopFunc< A >* hop = + dynamic_cast< const GetHopFunc< A >* >( op2 ); + hop->opGetVec( tgt.eref(), vec, gof ); + delete op2; + return; + } + cout << "Warning: Field::getVec conversion error for " << + dest.path() << endl; + } + + /** + * Blocking call for finding a value and returning in a + * string. + */ + static bool innerStrGet( const ObjId& dest, const string& field, + string& str ) + { + Conv< A >::val2str( str, get( dest, field ) ); + return 1; + } }; /** @@ -355,95 +380,102 @@ template< class A > class Field: public SetGet1< A > */ template< class A1, class A2 > class SetGet2: public SetGet { - public: - SetGet2() - {;} - - /** - * Blocking, typed 'Set' call - */ - static bool set( const ObjId& dest, const string& field, - A1 arg1, A2 arg2 ) - { - FuncId fid; - ObjId tgt( dest ); - const OpFunc* func = checkSet( field, tgt, fid ); - const OpFunc2Base< A1, A2 >* op = - dynamic_cast< const OpFunc2Base< A1, A2 >* >( func ); - if ( op ) { - if ( tgt.isOffNode() ) { - const OpFunc* op2 = op->makeHopFunc( - HopIndex( op->opIndex(), MooseSetHop ) ); - const OpFunc2Base< A1, A2 >* hop = - dynamic_cast< const OpFunc2Base< A1, A2 >* >( op2 ); - hop->op( tgt.eref(), arg1, arg2 ); - delete op2; - if ( tgt.isGlobal() ) - op->op( tgt.eref(), arg1, arg2 ); - return true; - } else { - op->op( tgt.eref(), arg1, arg2 ); - return true; - } - } - return false; - } - - /** - * Assign a vector of targets, using matching vectors of arguments - * arg1 and arg2. Specifically, index i on the target receives - * arguments arg1[i], arg2[i]. - * Note that there is no requirement for the size of the - * argument vectors to be equal to the size of the target array - * of objects. If there are fewer arguments then the index cycles - * back, so as to tile the target array with as many arguments as - * we have. - * - * Not yet implemented correct handling for FieldElements. - */ - static bool setVec( Id destId, const string& field, - const vector< A1 >& arg1, const vector< A2 >& arg2 ) - { - ObjId tgt( destId, 0 ); - FuncId fid; - const OpFunc* func = checkSet( field, tgt, fid ); - const OpFunc2Base< A1, A2 >* op = - dynamic_cast< const OpFunc2Base< A1, A2 >* >( func ); - if ( op ) { - /* - unsigned int size = tgt.element()->numData(); - // total # of entries on element and maybe to include fields - for ( unsigned int i = 0; i < size; ++i ) { - Eref er( tgt.element(), i ); - op->op( er, arg1[ i % arg1.size() ], - arg2[ i % arg2.size() ] ); - } - return true; - */ - const OpFunc* op2 = op->makeHopFunc( - HopIndex( op->opIndex(), MooseSetVecHop ) ); - const OpFunc2Base< A1, A2 >* hop = - dynamic_cast< const OpFunc2Base< A1, A2 >* >( op2 ); - hop->opVec( tgt.eref(), arg1, arg2, op ); - delete op2; - return true; - } - return false; - } - - /** - * Blocking call using string conversion. - */ - static bool innerStrSet( const ObjId& dest, const string& field, - const string& val ) - { - A1 arg1; - A2 arg2; - string::size_type pos = val.find_first_of( "," ); - Conv< A1 >::str2val( arg1, val.substr( 0, pos ) ); - Conv< A2 >::str2val( arg2, val.substr( pos + 1 ) ); - return set( dest, field, arg1, arg2 ); - } +public: + SetGet2() + { + ; + } + + /** + * Blocking, typed 'Set' call + */ + static bool set( const ObjId& dest, const string& field, + A1 arg1, A2 arg2 ) + { + FuncId fid; + ObjId tgt( dest ); + const OpFunc* func = checkSet( field, tgt, fid ); + const OpFunc2Base< A1, A2 >* op = + dynamic_cast< const OpFunc2Base< A1, A2 >* >( func ); + if ( op ) + { + if ( tgt.isOffNode() ) + { + const OpFunc* op2 = op->makeHopFunc( + HopIndex( op->opIndex(), MooseSetHop ) ); + const OpFunc2Base< A1, A2 >* hop = + dynamic_cast< const OpFunc2Base< A1, A2 >* >( op2 ); + hop->op( tgt.eref(), arg1, arg2 ); + delete op2; + if ( tgt.isGlobal() ) + op->op( tgt.eref(), arg1, arg2 ); + return true; + } + else + { + op->op( tgt.eref(), arg1, arg2 ); + return true; + } + } + return false; + } + + /** + * Assign a vector of targets, using matching vectors of arguments + * arg1 and arg2. Specifically, index i on the target receives + * arguments arg1[i], arg2[i]. + * Note that there is no requirement for the size of the + * argument vectors to be equal to the size of the target array + * of objects. If there are fewer arguments then the index cycles + * back, so as to tile the target array with as many arguments as + * we have. + * + * Not yet implemented correct handling for FieldElements. + */ + static bool setVec( Id destId, const string& field, + const vector< A1 >& arg1, const vector< A2 >& arg2 ) + { + ObjId tgt( destId, 0 ); + FuncId fid; + const OpFunc* func = checkSet( field, tgt, fid ); + const OpFunc2Base< A1, A2 >* op = + dynamic_cast< const OpFunc2Base< A1, A2 >* >( func ); + if ( op ) + { + /* + unsigned int size = tgt.element()->numData(); + // total # of entries on element and maybe to include fields + for ( unsigned int i = 0; i < size; ++i ) { + Eref er( tgt.element(), i ); + op->op( er, arg1[ i % arg1.size() ], + arg2[ i % arg2.size() ] ); + } + return true; + */ + const OpFunc* op2 = op->makeHopFunc( + HopIndex( op->opIndex(), MooseSetVecHop ) ); + const OpFunc2Base< A1, A2 >* hop = + dynamic_cast< const OpFunc2Base< A1, A2 >* >( op2 ); + hop->opVec( tgt.eref(), arg1, arg2, op ); + delete op2; + return true; + } + return false; + } + + /** + * Blocking call using string conversion. + */ + static bool innerStrSet( const ObjId& dest, const string& field, + const string& val ) + { + A1 arg1; + A2 arg2; + string::size_type pos = val.find_first_of( "," ); + Conv< A1 >::str2val( arg1, val.substr( 0, pos ) ); + Conv< A2 >::str2val( arg2, val.substr( pos + 1 ) ); + return set( dest, field, arg1, arg2 ); + } }; /** @@ -456,159 +488,167 @@ template< class A1, class A2 > class SetGet2: public SetGet */ template< class L, class A > class LookupField: public SetGet2< L, A > { - public: - LookupField( const ObjId& dest ) - : SetGet2< L, A >( dest ) - {;} - - /** - * Blocking, typed 'Set' call. Identical to SetGet2::set. - */ - static bool set( const ObjId& dest, const string& field, - L index, A arg ) - { - string temp = "set" + field; - temp[3] = std::toupper( temp[3] ); - return SetGet2< L, A >::set( dest, temp, index, arg ); - } - - /** - * This setVec assigns goes through each object entry in the - * destId, and assigns the corresponding index and argument to it. - */ - static bool setVec( Id destId, const string& field, - const vector< L >& index, const vector< A >& arg ) - { - string temp = "set" + field; - temp[3] = std::toupper( temp[3] ); - return SetGet2< L, A >::setVec( destId, temp, index, arg ); - } - - /** - * This setVec takes a specific object entry, presumably one with - * an array of values within it. The it goes through each specified - * index and assigns the corresponding argument. - * This is a brute-force assignment. - */ - static bool setVec( ObjId dest, const string& field, - const vector< L >& index, const vector< A >& arg ) - { - string temp = "set" + field; - temp[3] = std::toupper( temp[3] ); - return SetGet2< L, A >::setVec( dest, temp, index, arg ); - } - - /** - * Faking setRepeat too. Just plugs into setVec. - */ - static bool setRepeat( Id destId, const string& field, - const vector< L >& index, A arg ) - { - vector< A > avec( index.size(), arg ); - return setVec( destId, field, index, avec ); - } - - /** - * Blocking call using string conversion - */ - static bool innerStrSet( const ObjId& dest, const string& field, - const string& indexStr, const string& val ) - { - L index; - Conv< L >::str2val( index, indexStr ); - - A arg; - // Do NOT add 'set_' to the field name, as the 'set' func - // does it anyway. - Conv< A >::str2val( arg, val ); - return set( dest, field, index, arg ); - } - - /** - * Gets a value on a specific object, looking it up using the - * provided index. - */ - // Returns a field value. - static A get( const ObjId& dest, const string& field, L index ) - { - ObjId tgt( dest ); - FuncId fid; - string fullFieldName = "get" + field; - fullFieldName[3] = std::toupper( fullFieldName[3] ); - const OpFunc* func = SetGet::checkSet( fullFieldName, tgt, fid); - const LookupGetOpFuncBase< L, A >* gof = - dynamic_cast< const LookupGetOpFuncBase< L, A >* >( func ); - if ( gof ) { - if ( tgt.isDataHere() ) { - return gof->returnOp( tgt.eref(), index ); - } else { - /* - const OpFunc* op2 = gof->makeHopFunc( - HopIndex( gof->opIndex(), MooseGetHop ), index ); - const OpFunc1Base< A* >* hop = - dynamic_cast< const OpFunc1Base< A* >* >( op2 ); - */ - cout << "Warning: LookupField::get: cannot cross nodes yet\n"; - return A(); - /* - assert( hop ); - // Blocking function. - hop->op( tgt.eref(), &ret ); - delete op2; - return ret; - */ - } - } - cout << "LookupField::get: Warning: Field::Get conversion error for " << - dest.id.path() << "." << field << endl; - return A(); - } - - /** - * Blocking call that returns a vector of values in vec. - * This variant goes through each target object entry on dest, - * and passes in the same lookup index to each one. The results - * are put together in the vector vec. - */ - static void getVec( Id dest, const string& field, - vector< L >& index, vector< A >& vec ) - { - vec.resize( 0 ); - ObjId tgt( dest ); - FuncId fid; - string fullFieldName = "get" + field; - fullFieldName[3] = std::toupper( fullFieldName[3] ); - const OpFunc* func = SetGet::checkSet( fullFieldName, tgt, fid ); - const LookupGetOpFuncBase< L, A >* gof = - dynamic_cast< const LookupGetOpFuncBase< L, A >* >( func ); - if ( gof ) { - Element* elm = dest.element(); - unsigned int size = vec.size(); // temporary. See SetVec. - vec.resize( size ); - for ( unsigned int i = 0; i < size; ++i ) { - Eref e( elm, i ); - vec[i] = gof->returnOp( e, index ); - } - return; - } - cout << "Warning: Field::getVec conversion error for " << - dest.path() << endl; - } - - /** - * Blocking virtual call for finding a value and returning in a - * string. - */ - static bool innerStrGet( const ObjId& dest, const string& field, - const string& indexStr, string& str ) - { - L index; - Conv< L >::str2val( index, indexStr ); - - A ret = get( dest, field, index ); - Conv<A>::val2str( str, ret ); - return 1; - } +public: + LookupField( const ObjId& dest ) + : SetGet2< L, A >( dest ) + { + ; + } + + /** + * Blocking, typed 'Set' call. Identical to SetGet2::set. + */ + static bool set( const ObjId& dest, const string& field, + L index, A arg ) + { + string temp = "set" + field; + temp[3] = std::toupper( temp[3] ); + return SetGet2< L, A >::set( dest, temp, index, arg ); + } + + /** + * This setVec assigns goes through each object entry in the + * destId, and assigns the corresponding index and argument to it. + */ + static bool setVec( Id destId, const string& field, + const vector< L >& index, const vector< A >& arg ) + { + string temp = "set" + field; + temp[3] = std::toupper( temp[3] ); + return SetGet2< L, A >::setVec( destId, temp, index, arg ); + } + + /** + * This setVec takes a specific object entry, presumably one with + * an array of values within it. The it goes through each specified + * index and assigns the corresponding argument. + * This is a brute-force assignment. + */ + static bool setVec( ObjId dest, const string& field, + const vector< L >& index, const vector< A >& arg ) + { + string temp = "set" + field; + temp[3] = std::toupper( temp[3] ); + return SetGet2< L, A >::setVec( dest, temp, index, arg ); + } + + /** + * Faking setRepeat too. Just plugs into setVec. + */ + static bool setRepeat( Id destId, const string& field, + const vector< L >& index, A arg ) + { + vector< A > avec( index.size(), arg ); + return setVec( destId, field, index, avec ); + } + + /** + * Blocking call using string conversion + */ + static bool innerStrSet( const ObjId& dest, const string& field, + const string& indexStr, const string& val ) + { + L index; + Conv< L >::str2val( index, indexStr ); + + A arg; + // Do NOT add 'set_' to the field name, as the 'set' func + // does it anyway. + Conv< A >::str2val( arg, val ); + return set( dest, field, index, arg ); + } + + /** + * Gets a value on a specific object, looking it up using the + * provided index. + */ + // Returns a field value. + static A get( const ObjId& dest, const string& field, L index ) + { + ObjId tgt( dest ); + FuncId fid; + string fullFieldName = "get" + field; + fullFieldName[3] = std::toupper( fullFieldName[3] ); + const OpFunc* func = SetGet::checkSet( fullFieldName, tgt, fid); + const LookupGetOpFuncBase< L, A >* gof = + dynamic_cast< const LookupGetOpFuncBase< L, A >* >( func ); + if ( gof ) + { + if ( tgt.isDataHere() ) + { + return gof->returnOp( tgt.eref(), index ); + } + else + { + /* + const OpFunc* op2 = gof->makeHopFunc( + HopIndex( gof->opIndex(), MooseGetHop ), index ); + const OpFunc1Base< A* >* hop = + dynamic_cast< const OpFunc1Base< A* >* >( op2 ); + */ + cout << "Warning: LookupField::get: cannot cross nodes yet\n"; + return A(); + /* + assert( hop ); + // Blocking function. + hop->op( tgt.eref(), &ret ); + delete op2; + return ret; + */ + } + } + cout << "LookupField::get: Warning: Field::Get conversion error for " << + dest.id.path() << "." << field << endl; + return A(); + } + + /** + * Blocking call that returns a vector of values in vec. + * This variant goes through each target object entry on dest, + * and passes in the same lookup index to each one. The results + * are put together in the vector vec. + */ + static void getVec( Id dest, const string& field, + vector< L >& index, vector< A >& vec ) + { + vec.resize( 0 ); + ObjId tgt( dest ); + FuncId fid; + string fullFieldName = "get" + field; + fullFieldName[3] = std::toupper( fullFieldName[3] ); + const OpFunc* func = SetGet::checkSet( fullFieldName, tgt, fid ); + const LookupGetOpFuncBase< L, A >* gof = + dynamic_cast< const LookupGetOpFuncBase< L, A >* >( func ); + if ( gof ) + { + Element* elm = dest.element(); + unsigned int size = vec.size(); // temporary. See SetVec. + vec.resize( size ); + for ( unsigned int i = 0; i < size; ++i ) + { + Eref e( elm, i ); + vec[i] = gof->returnOp( e, index ); + } + return; + } + cout << "Warning: Field::getVec conversion error for " << + dest.path() << endl; + } + + /** + * Blocking virtual call for finding a value and returning in a + * string. + */ + static bool innerStrGet( const ObjId& dest, const string& field, + const string& indexStr, string& str ) + { + L index; + Conv< L >::str2val( index, indexStr ); + + A ret = get( dest, field, index ); + Conv<A>::val2str( str, ret ); + return 1; + } }; /** @@ -616,60 +656,66 @@ template< class L, class A > class LookupField: public SetGet2< L, A > */ template< class A1, class A2, class A3 > class SetGet3: public SetGet { - public: - SetGet3() - {;} - - /** - * Blocking, typed 'Set' call - */ - static bool set( const ObjId& dest, const string& field, - A1 arg1, A2 arg2, A3 arg3 ) - { - FuncId fid; - ObjId tgt( dest ); - const OpFunc* func = checkSet( field, tgt, fid ); - const OpFunc3Base< A1, A2, A3 >* op = - dynamic_cast< const OpFunc3Base< A1, A2, A3 >* >( func); - if ( op ) { - if ( tgt.isOffNode() ) { - const OpFunc* op2 = op->makeHopFunc( - HopIndex( op->opIndex(), MooseSetHop ) ); - const OpFunc3Base< A1, A2, A3 >* hop = - dynamic_cast< const OpFunc3Base< A1, A2, A3 >* >( - op2 ); - hop->op( tgt.eref(), arg1, arg2, arg3 ); - delete op2; - if ( tgt.isGlobal() ) - op->op( tgt.eref(), arg1, arg2, arg3 ); - return true; - } else { - op->op( tgt.eref(), arg1, arg2, arg3 ); - return true; - } - } - return 0; - } - - /** - * Blocking call using string conversion. - * As yet we don't have 2 arg conversion from a single string. - * So this is a dummy - */ - static bool innerStrSet( const ObjId& dest, const string& field, - const string& val ) - { - A1 arg1; - A2 arg2; - A3 arg3; - string::size_type pos = val.find_first_of( "," ); - Conv< A1 >::str2val( arg1, val.substr( 0, pos ) ); - string temp = val.substr( pos + 1 ); - pos = temp.find_first_of( "," ); - Conv< A2 >::str2val( arg2, temp.substr( 0,pos ) ); - Conv< A3 >::str2val( arg3, temp.substr( pos + 1 ) ); - return set( dest, field, arg1, arg2, arg3 ); - } +public: + SetGet3() + { + ; + } + + /** + * Blocking, typed 'Set' call + */ + static bool set( const ObjId& dest, const string& field, + A1 arg1, A2 arg2, A3 arg3 ) + { + FuncId fid; + ObjId tgt( dest ); + const OpFunc* func = checkSet( field, tgt, fid ); + const OpFunc3Base< A1, A2, A3 >* op = + dynamic_cast< const OpFunc3Base< A1, A2, A3 >* >( func); + if ( op ) + { + if ( tgt.isOffNode() ) + { + const OpFunc* op2 = op->makeHopFunc( + HopIndex( op->opIndex(), MooseSetHop ) ); + const OpFunc3Base< A1, A2, A3 >* hop = + dynamic_cast< const OpFunc3Base< A1, A2, A3 >* >( + op2 ); + hop->op( tgt.eref(), arg1, arg2, arg3 ); + delete op2; + if ( tgt.isGlobal() ) + op->op( tgt.eref(), arg1, arg2, arg3 ); + return true; + } + else + { + op->op( tgt.eref(), arg1, arg2, arg3 ); + return true; + } + } + return 0; + } + + /** + * Blocking call using string conversion. + * As yet we don't have 2 arg conversion from a single string. + * So this is a dummy + */ + static bool innerStrSet( const ObjId& dest, const string& field, + const string& val ) + { + A1 arg1; + A2 arg2; + A3 arg3; + string::size_type pos = val.find_first_of( "," ); + Conv< A1 >::str2val( arg1, val.substr( 0, pos ) ); + string temp = val.substr( pos + 1 ); + pos = temp.find_first_of( "," ); + Conv< A2 >::str2val( arg2, temp.substr( 0,pos ) ); + Conv< A3 >::str2val( arg3, temp.substr( pos + 1 ) ); + return set( dest, field, arg1, arg2, arg3 ); + } }; /** @@ -677,200 +723,218 @@ template< class A1, class A2, class A3 > class SetGet3: public SetGet */ template< class A1, class A2, class A3, class A4 > class SetGet4: public SetGet { - public: - SetGet4() - {;} - - /** - * Blocking, typed 'Set' call - */ - static bool set( const ObjId& dest, const string& field, - A1 arg1, A2 arg2, A3 arg3, A4 arg4 ) - { - FuncId fid; - ObjId tgt( dest ); - const OpFunc* func = checkSet( field, tgt, fid ); - const OpFunc4Base< A1, A2, A3, A4 >* op = - dynamic_cast< const OpFunc4Base< A1, A2, A3, A4 >* >( func); - if ( op ) { - if ( tgt.isOffNode() ) { - const OpFunc* op2 = op->makeHopFunc( - HopIndex( op->opIndex(), MooseSetHop ) ); - const OpFunc4Base< A1, A2, A3, A4 >* hop = - dynamic_cast< const OpFunc4Base< A1, A2, A3, A4 >* >( op2 ); - hop->op( tgt.eref(), arg1, arg2, arg3, arg4 ); - delete op2; - if ( tgt.isGlobal() ) - op->op( tgt.eref(), arg1, arg2, arg3, arg4 ); - return true; - } else { - op->op( tgt.eref(), arg1, arg2, arg3, arg4 ); - return true; - } - } - return 0; - } - - /** - * Blocking call using string conversion. - * As yet we don't have 2 arg conversion from a single string. - * So this is a dummy - */ - static bool innerStrSet( const ObjId& dest, const string& field, - const string& val ) - { - A1 arg1; - A2 arg2; - A3 arg3; - A4 arg4; - string::size_type pos = val.find_first_of( "," ); - Conv< A1 >::str2val( arg1, val.substr( 0, pos ) ); - string temp = val.substr( pos + 1 ); - pos = temp.find_first_of( "," ); - Conv< A2 >::str2val( arg2, temp.substr( 0, pos ) ); - temp = temp.substr( pos + 1 ); - pos = temp.find_first_of( "," ); - Conv< A3 >::str2val( arg3, temp.substr( 0, pos ) ); - Conv< A4 >::str2val( arg4, temp.substr( pos + 1 ) ); - return set( dest, field, arg1, arg2, arg3, arg4 ); - } +public: + SetGet4() + { + ; + } + + /** + * Blocking, typed 'Set' call + */ + static bool set( const ObjId& dest, const string& field, + A1 arg1, A2 arg2, A3 arg3, A4 arg4 ) + { + FuncId fid; + ObjId tgt( dest ); + const OpFunc* func = checkSet( field, tgt, fid ); + const OpFunc4Base< A1, A2, A3, A4 >* op = + dynamic_cast< const OpFunc4Base< A1, A2, A3, A4 >* >( func); + if ( op ) + { + if ( tgt.isOffNode() ) + { + const OpFunc* op2 = op->makeHopFunc( + HopIndex( op->opIndex(), MooseSetHop ) ); + const OpFunc4Base< A1, A2, A3, A4 >* hop = + dynamic_cast< const OpFunc4Base< A1, A2, A3, A4 >* >( op2 ); + hop->op( tgt.eref(), arg1, arg2, arg3, arg4 ); + delete op2; + if ( tgt.isGlobal() ) + op->op( tgt.eref(), arg1, arg2, arg3, arg4 ); + return true; + } + else + { + op->op( tgt.eref(), arg1, arg2, arg3, arg4 ); + return true; + } + } + return 0; + } + + /** + * Blocking call using string conversion. + * As yet we don't have 2 arg conversion from a single string. + * So this is a dummy + */ + static bool innerStrSet( const ObjId& dest, const string& field, + const string& val ) + { + A1 arg1; + A2 arg2; + A3 arg3; + A4 arg4; + string::size_type pos = val.find_first_of( "," ); + Conv< A1 >::str2val( arg1, val.substr( 0, pos ) ); + string temp = val.substr( pos + 1 ); + pos = temp.find_first_of( "," ); + Conv< A2 >::str2val( arg2, temp.substr( 0, pos ) ); + temp = temp.substr( pos + 1 ); + pos = temp.find_first_of( "," ); + Conv< A3 >::str2val( arg3, temp.substr( 0, pos ) ); + Conv< A4 >::str2val( arg4, temp.substr( pos + 1 ) ); + return set( dest, field, arg1, arg2, arg3, arg4 ); + } }; /** * SetGet5 handles 5-argument Sets. It does not deal with Gets. */ template< class A1, class A2, class A3, class A4, class A5 > class SetGet5: - public SetGet + public SetGet { - public: - SetGet5() - {;} - - static bool set( const ObjId& dest, const string& field, - A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5 ) - { - FuncId fid; - ObjId tgt( dest ); - const OpFunc* func = checkSet( field, tgt, fid ); - const OpFunc5Base< A1, A2, A3, A4, A5 >* op = - dynamic_cast< const OpFunc5Base< A1, A2, A3, A4, A5 >* >( func); - if ( op ) { - if ( tgt.isOffNode() ) { - const OpFunc* op2 = op->makeHopFunc( - HopIndex( op->opIndex(), MooseSetHop ) ); - const OpFunc5Base< A1, A2, A3, A4, A5 >* hop = - dynamic_cast< const OpFunc5Base< A1, A2, A3, A4, A5 >* >( op2 ); - hop->op( tgt.eref(), arg1, arg2, arg3, arg4, arg5 ); - delete op2; - if ( tgt.isGlobal() ) - op->op( tgt.eref(), arg1, arg2, arg3, arg4, arg5 ); - return true; - } else { - op->op( tgt.eref(), arg1, arg2, arg3, arg4, arg5 ); - return true; - } - } - return 0; - } - - /** - * Blocking call using string conversion. - * As yet we don't have 2 arg conversion from a single string. - * So this is a dummy - */ - static bool innerStrSet( const ObjId& dest, const string& field, - const string& val ) - { - A1 arg1; - A2 arg2; - A3 arg3; - A4 arg4; - A5 arg5; - string::size_type pos = val.find_first_of( "," ); - Conv< A1 >::str2val( arg1, val.substr( 0, pos ) ); - string temp = val.substr( pos + 1 ); - pos = temp.find_first_of( "," ); - Conv< A2 >::str2val( arg2, temp.substr( 0, pos ) ); - temp = temp.substr( pos + 1 ); - pos = temp.find_first_of( "," ); - Conv< A3 >::str2val( arg3, temp.substr( 0, pos ) ); - temp = temp.substr( pos + 1 ); - pos = temp.find_first_of( "," ); - Conv< A4 >::str2val( arg4, temp.substr( 0, pos ) ); - Conv< A5 >::str2val( arg5, temp.substr( pos + 1 ) ); - return set( dest, field, arg1, arg2, arg3, arg4, arg5 ); - } +public: + SetGet5() + { + ; + } + + static bool set( const ObjId& dest, const string& field, + A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5 ) + { + FuncId fid; + ObjId tgt( dest ); + const OpFunc* func = checkSet( field, tgt, fid ); + const OpFunc5Base< A1, A2, A3, A4, A5 >* op = + dynamic_cast< const OpFunc5Base< A1, A2, A3, A4, A5 >* >( func); + if ( op ) + { + if ( tgt.isOffNode() ) + { + const OpFunc* op2 = op->makeHopFunc( + HopIndex( op->opIndex(), MooseSetHop ) ); + const OpFunc5Base< A1, A2, A3, A4, A5 >* hop = + dynamic_cast< const OpFunc5Base< A1, A2, A3, A4, A5 >* >( op2 ); + hop->op( tgt.eref(), arg1, arg2, arg3, arg4, arg5 ); + delete op2; + if ( tgt.isGlobal() ) + op->op( tgt.eref(), arg1, arg2, arg3, arg4, arg5 ); + return true; + } + else + { + op->op( tgt.eref(), arg1, arg2, arg3, arg4, arg5 ); + return true; + } + } + return 0; + } + + /** + * Blocking call using string conversion. + * As yet we don't have 2 arg conversion from a single string. + * So this is a dummy + */ + static bool innerStrSet( const ObjId& dest, const string& field, + const string& val ) + { + A1 arg1; + A2 arg2; + A3 arg3; + A4 arg4; + A5 arg5; + string::size_type pos = val.find_first_of( "," ); + Conv< A1 >::str2val( arg1, val.substr( 0, pos ) ); + string temp = val.substr( pos + 1 ); + pos = temp.find_first_of( "," ); + Conv< A2 >::str2val( arg2, temp.substr( 0, pos ) ); + temp = temp.substr( pos + 1 ); + pos = temp.find_first_of( "," ); + Conv< A3 >::str2val( arg3, temp.substr( 0, pos ) ); + temp = temp.substr( pos + 1 ); + pos = temp.find_first_of( "," ); + Conv< A4 >::str2val( arg4, temp.substr( 0, pos ) ); + Conv< A5 >::str2val( arg5, temp.substr( pos + 1 ) ); + return set( dest, field, arg1, arg2, arg3, arg4, arg5 ); + } }; /** * SetGet6 handles 6-argument Sets. It does not deal with Gets. */ template< class A1, class A2, class A3, class A4, class A5, class A6 > class SetGet6: - public SetGet + public SetGet { - public: - SetGet6() - {;} - - /** - * Blocking, typed 'Set' call - */ - static bool set( const ObjId& dest, const string& field, - A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5, A6 arg6 ) - { - FuncId fid; - ObjId tgt( dest ); - const OpFunc* func = checkSet( field, tgt, fid ); - const OpFunc6Base< A1, A2, A3, A4, A5, A6 >* op = - dynamic_cast< const OpFunc6Base< A1, A2, A3, A4, A5, A6 >* >( func); - if ( op ) { - if ( tgt.isOffNode() ) { - const OpFunc* op2 = op->makeHopFunc( - HopIndex( op->opIndex(), MooseSetHop ) ); - const OpFunc6Base< A1, A2, A3, A4, A5, A6 >* hop = - dynamic_cast< const OpFunc6Base< A1, A2, A3, A4, A5, A6 >* >( op2 ); - hop->op( tgt.eref(), arg1, arg2, arg3, arg4, arg5, arg6 ); - delete op2; - if ( tgt.isGlobal() ) - op->op( tgt.eref(), arg1, arg2, arg3, arg4, arg5, arg6 ); - return true; - } else { - op->op( tgt.eref(), arg1, arg2, arg3, arg4, arg5, arg6); - return true; - } - } - return 0; - } - - /** - * Blocking call using string conversion. - */ - static bool innerStrSet( const ObjId& dest, const string& field, - const string& val ) - { - A1 arg1; - A2 arg2; - A3 arg3; - A4 arg4; - A5 arg5; - A6 arg6; - string::size_type pos = val.find_first_of( "," ); - Conv< A1 >::str2val( arg1, val.substr( 0, pos ) ); - string temp = val.substr( pos + 1 ); - pos = temp.find_first_of( "," ); - Conv< A2 >::str2val( arg2, temp.substr( 0, pos ) ); - temp = temp.substr( pos + 1 ); - pos = temp.find_first_of( "," ); - Conv< A3 >::str2val( arg3, temp.substr( 0, pos ) ); - temp = temp.substr( pos + 1 ); - pos = temp.find_first_of( "," ); - Conv< A4 >::str2val( arg4, temp.substr( 0, pos ) ); - temp = temp.substr( pos + 1 ); - pos = temp.find_first_of( "," ); - Conv< A5 >::str2val( arg5, temp.substr( 0, pos ) ); - Conv< A6 >::str2val( arg6, temp.substr( pos + 1 ) ); - return set( dest, field, arg1, arg2, arg3, arg4, arg5, arg6 ); - } +public: + SetGet6() + { + ; + } + + /** + * Blocking, typed 'Set' call + */ + static bool set( const ObjId& dest, const string& field, + A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5, A6 arg6 ) + { + FuncId fid; + ObjId tgt( dest ); + const OpFunc* func = checkSet( field, tgt, fid ); + const OpFunc6Base< A1, A2, A3, A4, A5, A6 >* op = + dynamic_cast< const OpFunc6Base< A1, A2, A3, A4, A5, A6 >* >( func); + if ( op ) + { + if ( tgt.isOffNode() ) + { + const OpFunc* op2 = op->makeHopFunc( + HopIndex( op->opIndex(), MooseSetHop ) ); + const OpFunc6Base< A1, A2, A3, A4, A5, A6 >* hop = + dynamic_cast< const OpFunc6Base< A1, A2, A3, A4, A5, A6 >* >( op2 ); + hop->op( tgt.eref(), arg1, arg2, arg3, arg4, arg5, arg6 ); + delete op2; + if ( tgt.isGlobal() ) + op->op( tgt.eref(), arg1, arg2, arg3, arg4, arg5, arg6 ); + return true; + } + else + { + op->op( tgt.eref(), arg1, arg2, arg3, arg4, arg5, arg6); + return true; + } + } + return 0; + } + + /** + * Blocking call using string conversion. + */ + static bool innerStrSet( const ObjId& dest, const string& field, + const string& val ) + { + A1 arg1; + A2 arg2; + A3 arg3; + A4 arg4; + A5 arg5; + A6 arg6; + string::size_type pos = val.find_first_of( "," ); + Conv< A1 >::str2val( arg1, val.substr( 0, pos ) ); + string temp = val.substr( pos + 1 ); + pos = temp.find_first_of( "," ); + Conv< A2 >::str2val( arg2, temp.substr( 0, pos ) ); + temp = temp.substr( pos + 1 ); + pos = temp.find_first_of( "," ); + Conv< A3 >::str2val( arg3, temp.substr( 0, pos ) ); + temp = temp.substr( pos + 1 ); + pos = temp.find_first_of( "," ); + Conv< A4 >::str2val( arg4, temp.substr( 0, pos ) ); + temp = temp.substr( pos + 1 ); + pos = temp.find_first_of( "," ); + Conv< A5 >::str2val( arg5, temp.substr( 0, pos ) ); + Conv< A6 >::str2val( arg6, temp.substr( pos + 1 ) ); + return set( dest, field, arg1, arg2, arg3, arg4, arg5, arg6 ); + } }; #endif // _SETGET_H diff --git a/biophysics/CaConcBase.cpp b/biophysics/CaConcBase.cpp index c95c386a..1f974bb3 100644 --- a/biophysics/CaConcBase.cpp +++ b/biophysics/CaConcBase.cpp @@ -12,6 +12,8 @@ #include "../basecode/ElementValueFinfo.h" #include "CaConcBase.h" +#define VALENCE 2 + /////////////////////////////////////////////////////// // MsgSrc definitions /////////////////////////////////////////////////////// @@ -76,7 +78,7 @@ const Cinfo* CaConcBase::initCinfo() "Volume scaling factor. " "Deprecated. This is a legacy field from GENESIS and exposes " "internal calculations. Please do not use. \n" - "B = 1/(vol * F) so that it obeys:\n" + "B = 1/(vol * F* VALENCE) so that it obeys:\n" "dC/dt = B*I_Ca - C/tau", &CaConcBase::setB, &CaConcBase::getB @@ -260,7 +262,7 @@ void CaConcBase::updateDimensions( const Eref& e ) double coreRadius = diameter_ / 2.0 - thickness_; vol -= PI * coreRadius * coreRadius * length_; } - double B = 1.0 / ( FaradayConst * vol ); + double B = 1.0 / ( VALENCE* FaradayConst * vol ); vSetB( e, B ); } diff --git a/biophysics/HHGate.cpp b/biophysics/HHGate.cpp index 0e8ca584..eadfeca8 100644 --- a/biophysics/HHGate.cpp +++ b/biophysics/HHGate.cpp @@ -15,209 +15,209 @@ static const double SINGULARITY = 1.0e-6; const Cinfo* HHGate::initCinfo() { - /////////////////////////////////////////////////////// - // Field definitions. - /////////////////////////////////////////////////////// - static ReadOnlyLookupValueFinfo< HHGate, double, double > A( "A", - "lookupA: Look up the A gate value from a double. Usually does" - "so by direct scaling and offset to an integer lookup, using" - "a fine enough table granularity that there is little error." - "Alternatively uses linear interpolation." - "The range of the double is predefined based on knowledge of" - "voltage or conc ranges, and the granularity is specified by" - "the xmin, xmax, and dV fields.", - &HHGate::lookupA ); - static ReadOnlyLookupValueFinfo< HHGate, double, double > B( "B", - "lookupB: Look up the B gate value from a double." - "Note that this looks up the raw tables, which are transformed" - "from the reference parameters.", - &HHGate::lookupB ); - - static ElementValueFinfo< HHGate, vector< double > > alpha( "alpha", - "Parameters for voltage-dependent rates, alpha:" - "Set up alpha term using 5 parameters, as follows:" - "y(x) = (A + B * x) / (C + exp((x + D) / F))" - "The original HH equations can readily be cast into this form", - &HHGate::setAlpha, - &HHGate::getAlpha - ); - - static ElementValueFinfo< HHGate, vector< double > > beta( "beta", - "Parameters for voltage-dependent rates, beta:" - "Set up beta term using 5 parameters, as follows:" - "y(x) = (A + B * x) / (C + exp((x + D) / F))" - "The original HH equations can readily be cast into this form", - &HHGate::setBeta, - &HHGate::getBeta - ); - - static ElementValueFinfo< HHGate, vector< double > > tau( "tau", - "Parameters for voltage-dependent rates, tau:" - "Set up tau curve using 5 parameters, as follows:" - "y(x) = (A + B * x) / (C + exp((x + D) / F))", - &HHGate::setTau, - &HHGate::getTau - ); - - static ElementValueFinfo< HHGate, vector< double > > mInfinity( - "mInfinity", - "Parameters for voltage-dependent rates, mInfinity:" - "Set up mInfinity curve using 5 parameters, as follows:" - "y(x) = (A + B * x) / (C + exp((x + D) / F))" - "The original HH equations can readily be cast into this form", - &HHGate::setMinfinity, - &HHGate::getMinfinity - ); - - static ElementValueFinfo< HHGate, double > min( "min", - "Minimum range for lookup", - &HHGate::setMin, - &HHGate::getMin - ); - - static ElementValueFinfo< HHGate, double > max( "max", - "Minimum range for lookup", - &HHGate::setMax, - &HHGate::getMax - ); - - static ElementValueFinfo< HHGate, unsigned int > divs( "divs", - "Divisions for lookup. Zero means to use linear interpolation", - &HHGate::setDivs, - &HHGate::getDivs - ); - - static ElementValueFinfo< HHGate, vector< double > > tableA( - "tableA", - "Table of A entries", - &HHGate::setTableA, - &HHGate::getTableA - ); - - static ElementValueFinfo< HHGate, vector< double > > tableB( - "tableB", - "Table of alpha + beta entries", - &HHGate::setTableB, - &HHGate::getTableB - ); - - static ElementValueFinfo< HHGate, bool > useInterpolation( - "useInterpolation", - "Flag: use linear interpolation if true, else direct lookup", - &HHGate::setUseInterpolation, - &HHGate::getUseInterpolation - ); - - static ElementValueFinfo< HHGate, vector< double > > alphaParms( - "alphaParms", - "Set up both gates using 13 parameters, as follows:" - "setupAlpha AA AB AC AD AF BA BB BC BD BF xdivs xmin xmax" - "Here AA-AF are Coefficients A to F of the alpha (forward) term" - "Here BA-BF are Coefficients A to F of the beta (reverse) term" - "Here xdivs is the number of entries in the table," - "xmin and xmax define the range for lookup." - "Outside this range the returned value will be the low [high]" - "entry of the table." - "The equation describing each table is:" - "y(x) = (A + B * x) / (C + exp((x + D) / F))" - "The original HH equations can readily be cast into this form", - &HHGate::setupAlpha, - &HHGate::getAlphaParms - ); - - /////////////////////////////////////////////////////// - // DestFinfos - /////////////////////////////////////////////////////// - static DestFinfo setupAlpha( "setupAlpha", - "Set up both gates using 13 parameters, as follows:" - "setupAlpha AA AB AC AD AF BA BB BC BD BF xdivs xmin xmax" - "Here AA-AF are Coefficients A to F of the alpha (forward) term" - "Here BA-BF are Coefficients A to F of the beta (reverse) term" - "Here xdivs is the number of entries in the table," - "xmin and xmax define the range for lookup." - "Outside this range the returned value will be the low [high]" - "entry of the table." - "The equation describing each table is:" - "y(x) = (A + B * x) / (C + exp((x + D) / F))" - "The original HH equations can readily be cast into this form", - new EpFunc1< HHGate, vector< double > >( &HHGate::setupAlpha ) - ); - static DestFinfo setupTau( "setupTau", - "Identical to setupAlpha, except that the forms specified by" - "the 13 parameters are for the tau and m-infinity curves rather" - "than the alpha and beta terms. So the parameters are:" - "setupTau TA TB TC TD TF MA MB MC MD MF xdivs xmin xmax" - "As before, the equation describing each curve is:" - "y(x) = (A + B * x) / (C + exp((x + D) / F))", - new EpFunc1< HHGate, vector< double > >( &HHGate::setupTau ) - ); - static DestFinfo tweakAlpha( "tweakAlpha", - "Dummy function for backward compatibility. It used to convert" - "the tables from alpha, beta values to alpha, alpha+beta" - "because the internal calculations used these forms. Not" - "needed now, deprecated.", - new OpFunc0< HHGate >( &HHGate::tweakAlpha ) - ); - static DestFinfo tweakTau( "tweakTau", - "Dummy function for backward compatibility. It used to convert" - "the tables from tau, minf values to alpha, alpha+beta" - "because the internal calculations used these forms. Not" - "needed now, deprecated.", - new OpFunc0< HHGate >( &HHGate::tweakTau ) - ); - static DestFinfo setupGate( "setupGate", - "Sets up one gate at a time using the alpha/beta form." - "Has 9 parameters, as follows:" - "setupGate A B C D F xdivs xmin xmax is_beta" - "This sets up the gate using the equation:" - "y(x) = (A + B * x) / (C + exp((x + D) / F))" - "Deprecated.", - new EpFunc1< HHGate, vector< double > >( &HHGate::setupGate ) - ); - static Finfo* HHGateFinfos[] = - { - &A, // ReadOnlyLookupValue - &B, // ReadOnlyLookupValue - &alpha, // ElementValue - &beta, // ElementValue - &tau, // ElementValue - &mInfinity, // ElementValue - &min, // ElementValue - &max, // ElementValue - &divs, // ElementValue - &tableA, // ElementValue - &tableB, // ElementValue - &useInterpolation, // ElementValue - &alphaParms, // ElementValue - &setupAlpha, // Dest - &setupTau, // Dest - &tweakAlpha, // Dest - &tweakTau, // Dest - &setupGate, // Dest + /////////////////////////////////////////////////////// + // Field definitions. + /////////////////////////////////////////////////////// + static ReadOnlyLookupValueFinfo< HHGate, double, double > A( "A", + "lookupA: Look up the A gate value from a double. Usually does" + "so by direct scaling and offset to an integer lookup, using" + "a fine enough table granularity that there is little error." + "Alternatively uses linear interpolation." + "The range of the double is predefined based on knowledge of" + "voltage or conc ranges, and the granularity is specified by" + "the xmin, xmax, and dV fields.", + &HHGate::lookupA ); + static ReadOnlyLookupValueFinfo< HHGate, double, double > B( "B", + "lookupB: Look up the B gate value from a double." + "Note that this looks up the raw tables, which are transformed" + "from the reference parameters.", + &HHGate::lookupB ); + + static ElementValueFinfo< HHGate, vector< double > > alpha( "alpha", + "Parameters for voltage-dependent rates, alpha:" + "Set up alpha term using 5 parameters, as follows:" + "y(x) = (A + B * x) / (C + exp((x + D) / F))" + "The original HH equations can readily be cast into this form", + &HHGate::setAlpha, + &HHGate::getAlpha + ); + + static ElementValueFinfo< HHGate, vector< double > > beta( "beta", + "Parameters for voltage-dependent rates, beta:" + "Set up beta term using 5 parameters, as follows:" + "y(x) = (A + B * x) / (C + exp((x + D) / F))" + "The original HH equations can readily be cast into this form", + &HHGate::setBeta, + &HHGate::getBeta + ); + + static ElementValueFinfo< HHGate, vector< double > > tau( "tau", + "Parameters for voltage-dependent rates, tau:" + "Set up tau curve using 5 parameters, as follows:" + "y(x) = (A + B * x) / (C + exp((x + D) / F))", + &HHGate::setTau, + &HHGate::getTau + ); + + static ElementValueFinfo< HHGate, vector< double > > mInfinity( + "mInfinity", + "Parameters for voltage-dependent rates, mInfinity:" + "Set up mInfinity curve using 5 parameters, as follows:" + "y(x) = (A + B * x) / (C + exp((x + D) / F))" + "The original HH equations can readily be cast into this form", + &HHGate::setMinfinity, + &HHGate::getMinfinity + ); + + static ElementValueFinfo< HHGate, double > min( "min", + "Minimum range for lookup", + &HHGate::setMin, + &HHGate::getMin + ); + + static ElementValueFinfo< HHGate, double > max( "max", + "Minimum range for lookup", + &HHGate::setMax, + &HHGate::getMax + ); + + static ElementValueFinfo< HHGate, unsigned int > divs( "divs", + "Divisions for lookup. Zero means to use linear interpolation", + &HHGate::setDivs, + &HHGate::getDivs + ); + + static ElementValueFinfo< HHGate, vector< double > > tableA( + "tableA", + "Table of A entries", + &HHGate::setTableA, + &HHGate::getTableA + ); + + static ElementValueFinfo< HHGate, vector< double > > tableB( + "tableB", + "Table of alpha + beta entries", + &HHGate::setTableB, + &HHGate::getTableB + ); + + static ElementValueFinfo< HHGate, bool > useInterpolation( + "useInterpolation", + "Flag: use linear interpolation if true, else direct lookup", + &HHGate::setUseInterpolation, + &HHGate::getUseInterpolation + ); + + static ElementValueFinfo< HHGate, vector< double > > alphaParms( + "alphaParms", + "Set up both gates using 13 parameters, as follows:" + "setupAlpha AA AB AC AD AF BA BB BC BD BF xdivs xmin xmax" + "Here AA-AF are Coefficients A to F of the alpha (forward) term" + "Here BA-BF are Coefficients A to F of the beta (reverse) term" + "Here xdivs is the number of entries in the table," + "xmin and xmax define the range for lookup." + "Outside this range the returned value will be the low [high]" + "entry of the table." + "The equation describing each table is:" + "y(x) = (A + B * x) / (C + exp((x + D) / F))" + "The original HH equations can readily be cast into this form", + &HHGate::setupAlpha, + &HHGate::getAlphaParms + ); + + /////////////////////////////////////////////////////// + // DestFinfos + /////////////////////////////////////////////////////// + static DestFinfo setupAlpha( "setupAlpha", + "Set up both gates using 13 parameters, as follows:" + "setupAlpha AA AB AC AD AF BA BB BC BD BF xdivs xmin xmax" + "Here AA-AF are Coefficients A to F of the alpha (forward) term" + "Here BA-BF are Coefficients A to F of the beta (reverse) term" + "Here xdivs is the number of entries in the table," + "xmin and xmax define the range for lookup." + "Outside this range the returned value will be the low [high]" + "entry of the table." + "The equation describing each table is:" + "y(x) = (A + B * x) / (C + exp((x + D) / F))" + "The original HH equations can readily be cast into this form", + new EpFunc1< HHGate, vector< double > >( &HHGate::setupAlpha ) + ); + static DestFinfo setupTau( "setupTau", + "Identical to setupAlpha, except that the forms specified by" + "the 13 parameters are for the tau and m-infinity curves rather" + "than the alpha and beta terms. So the parameters are:" + "setupTau TA TB TC TD TF MA MB MC MD MF xdivs xmin xmax" + "As before, the equation describing each curve is:" + "y(x) = (A + B * x) / (C + exp((x + D) / F))", + new EpFunc1< HHGate, vector< double > >( &HHGate::setupTau ) + ); + static DestFinfo tweakAlpha( "tweakAlpha", + "Dummy function for backward compatibility. It used to convert" + "the tables from alpha, beta values to alpha, alpha+beta" + "because the internal calculations used these forms. Not" + "needed now, deprecated.", + new OpFunc0< HHGate >( &HHGate::tweakAlpha ) + ); + static DestFinfo tweakTau( "tweakTau", + "Dummy function for backward compatibility. It used to convert" + "the tables from tau, minf values to alpha, alpha+beta" + "because the internal calculations used these forms. Not" + "needed now, deprecated.", + new OpFunc0< HHGate >( &HHGate::tweakTau ) + ); + static DestFinfo setupGate( "setupGate", + "Sets up one gate at a time using the alpha/beta form." + "Has 9 parameters, as follows:" + "setupGate A B C D F xdivs xmin xmax is_beta" + "This sets up the gate using the equation:" + "y(x) = (A + B * x) / (C + exp((x + D) / F))" + "Deprecated.", + new EpFunc1< HHGate, vector< double > >( &HHGate::setupGate ) + ); + static Finfo* HHGateFinfos[] = + { + &A, // ReadOnlyLookupValue + &B, // ReadOnlyLookupValue + &alpha, // ElementValue + &beta, // ElementValue + &tau, // ElementValue + &mInfinity, // ElementValue + &min, // ElementValue + &max, // ElementValue + &divs, // ElementValue + &tableA, // ElementValue + &tableB, // ElementValue + &useInterpolation, // ElementValue + &alphaParms, // ElementValue + &setupAlpha, // Dest + &setupTau, // Dest + &tweakAlpha, // Dest + &tweakTau, // Dest + &setupGate, // Dest }; - static string doc[] = + static string doc[] = { - "Name", "HHGate", - "Author", "Upinder S. Bhalla, 2011, NCBS", - "Description", "HHGate: Gate for Hodkgin-Huxley type channels, equivalent to the " - "m and h terms on the Na squid channel and the n term on K. " - "This takes the voltage and state variable from the channel, " - "computes the new value of the state variable and a scaling, " - "depending on gate power, for the conductance.", + "Name", "HHGate", + "Author", "Upinder S. Bhalla, 2011, NCBS", + "Description", "HHGate: Gate for Hodkgin-Huxley type channels, equivalent to the " + "m and h terms on the Na squid channel and the n term on K. " + "This takes the voltage and state variable from the channel, " + "computes the new value of the state variable and a scaling, " + "depending on gate power, for the conductance.", }; - static Dinfo< HHGate > dinfo; - static Cinfo HHGateCinfo( - "HHGate", - Neutral::initCinfo(), - HHGateFinfos, sizeof(HHGateFinfos)/sizeof(Finfo *), - &dinfo, - doc, - sizeof(doc)/sizeof(string) - ); + static Dinfo< HHGate > dinfo; + static Cinfo HHGateCinfo( + "HHGate", + Neutral::initCinfo(), + HHGateFinfos, sizeof(HHGateFinfos)/sizeof(Finfo *), + &dinfo, + doc, + sizeof(doc)/sizeof(string) + ); - return &HHGateCinfo; + return &HHGateCinfo; } static const Cinfo* hhGateCinfo = HHGate::initCinfo(); @@ -225,22 +225,22 @@ static const Cinfo* hhGateCinfo = HHGate::initCinfo(); // Core class functions /////////////////////////////////////////////////// HHGate::HHGate() - : xmin_(0), xmax_(1), invDx_(1), - originalChanId_(0), - originalGateId_(0), - lookupByInterpolation_(0), - isDirectTable_(0) + : xmin_(0), xmax_(1), invDx_(1), + originalChanId_(0), + originalGateId_(0), + lookupByInterpolation_(0), + isDirectTable_(0) {;} HHGate::HHGate( Id originalChanId, Id originalGateId ) - : - A_( 1, 0.0 ), - B_( 1, 0.0 ), - xmin_(0), xmax_(1), invDx_(1), - originalChanId_( originalChanId ), - originalGateId_( originalGateId ), - lookupByInterpolation_(0), - isDirectTable_(0) + : + A_( 1, 0.0 ), + B_( 1, 0.0 ), + xmin_(0), xmax_(1), invDx_(1), + originalChanId_( originalChanId ), + originalGateId_( originalGateId ), + lookupByInterpolation_(0), + isDirectTable_(0) {;} /////////////////////////////////////////////////// @@ -249,272 +249,309 @@ HHGate::HHGate( Id originalChanId, Id originalGateId ) double HHGate::lookupTable( const vector< double >& tab, double v ) const { - if ( v <= xmin_ ) return tab[0]; - if ( v >= xmax_ ) return tab.back(); - if ( lookupByInterpolation_ ) { - unsigned int index = - static_cast< unsigned int >( ( v - xmin_ ) * invDx_ ); - assert( tab.size() > index ); - double frac = ( v - xmin_ - index / invDx_ ) * invDx_; - return tab[ index ] * ( 1 - frac ) + tab[ index + 1 ] * frac; - } else { - return tab[ static_cast< unsigned int >( (v - xmin_) * invDx_ ) ]; - } + if ( v <= xmin_ ) return tab[0]; + if ( v >= xmax_ ) return tab.back(); + if ( lookupByInterpolation_ ) + { + unsigned int index = + static_cast< unsigned int >( ( v - xmin_ ) * invDx_ ); + assert( tab.size() > index ); + double frac = ( v - xmin_ - index / invDx_ ) * invDx_; + return tab[ index ] * ( 1 - frac ) + tab[ index + 1 ] * frac; + } + else + { + return tab[ static_cast< unsigned int >( (v - xmin_) * invDx_ ) ]; + } } double HHGate::lookupA( double v ) const { - return lookupTable( A_, v ); + return lookupTable( A_, v ); } double HHGate::lookupB( double v ) const { - return lookupTable( B_, v ); + return lookupTable( B_, v ); } void HHGate::lookupBoth( double v, double* A, double* B ) const { - if ( v <= xmin_ ) { - *A = A_[0]; - *B = B_[0]; - } else if ( v >= xmax_ ) { - *A = A_.back(); - *B = B_.back(); - } else { - unsigned int index = - static_cast< unsigned int >( ( v - xmin_ ) * invDx_ ); - assert( A_.size() > index && B_.size() > index ); - if ( lookupByInterpolation_ ) { - double frac = ( v - xmin_ - index / invDx_ ) * invDx_; - *A = A_[ index ] * ( 1 - frac ) + A_[ index + 1 ] * frac; - *B = B_[ index ] * ( 1 - frac ) + B_[ index + 1 ] * frac; - } else { - *A = A_[ index ]; - *B = B_[ index ]; - } - } + if ( v <= xmin_ ) + { + *A = A_[0]; + *B = B_[0]; + } + else if ( v >= xmax_ ) + { + *A = A_.back(); + *B = B_.back(); + } + else + { + unsigned int index = + static_cast< unsigned int >( ( v - xmin_ ) * invDx_ ); + assert( A_.size() > index && B_.size() > index ); + if ( lookupByInterpolation_ ) + { + double frac = ( v - xmin_ - index / invDx_ ) * invDx_; + *A = A_[ index ] * ( 1 - frac ) + A_[ index + 1 ] * frac; + *B = B_[ index ] * ( 1 - frac ) + B_[ index + 1 ] * frac; + } + else + { + *A = A_[ index ]; + *B = B_[ index ]; + } + } } vector< double > HHGate::getAlpha( const Eref& e) const { - return alpha_; + return alpha_; } void HHGate::setAlpha( const Eref& e, vector< double > val ) { - if ( val.size() != 5 ) { - cout << "Error: HHGate::setAlpha on " << e.id().path() << - ": Number of entries on argument vector should be 5, was " << - val.size() << endl; - return; - } - if ( checkOriginal( e.id(), "alpha" ) ) { - alpha_ = val; - updateTauMinf(); - updateTables(); - } + if ( val.size() != 5 ) + { + cout << "Error: HHGate::setAlpha on " << e.id().path() << + ": Number of entries on argument vector should be 5, was " << + val.size() << endl; + return; + } + if ( checkOriginal( e.id(), "alpha" ) ) + { + alpha_ = val; + updateTauMinf(); + updateTables(); + } } vector< double > HHGate::getBeta( const Eref& e) const { - return beta_; + return beta_; } void HHGate::setBeta( const Eref& e, vector< double > val ) { - if ( val.size() != 5 ) { - cout << "Error: HHGate::setBeta on " << e.id().path() << - ": Number of entries on argument vector should be 5, was " << - val.size() << endl; - return; - } - if ( checkOriginal( e.id(), "beta" ) ) { - beta_ = val; - updateTauMinf(); - updateTables(); - } + if ( val.size() != 5 ) + { + cout << "Error: HHGate::setBeta on " << e.id().path() << + ": Number of entries on argument vector should be 5, was " << + val.size() << endl; + return; + } + if ( checkOriginal( e.id(), "beta" ) ) + { + beta_ = val; + updateTauMinf(); + updateTables(); + } } vector< double > HHGate::getTau( const Eref& e) const { - return tau_; + return tau_; } void HHGate::setTau( const Eref& e, vector< double > val ) { - if ( val.size() != 5 ) { - cout << "Error: HHGate::setTau on " << e.id().path() << - ": Number of entries on argument vector should be 5, was " << - val.size() << endl; - return; - } - if ( checkOriginal( e.id(), "tau" ) ) { - tau_ = val; - updateAlphaBeta(); - updateTables(); - } + if ( val.size() != 5 ) + { + cout << "Error: HHGate::setTau on " << e.id().path() << + ": Number of entries on argument vector should be 5, was " << + val.size() << endl; + return; + } + if ( checkOriginal( e.id(), "tau" ) ) + { + tau_ = val; + updateAlphaBeta(); + updateTables(); + } } vector< double > HHGate::getMinfinity( const Eref& e) const { - return mInfinity_; + return mInfinity_; } void HHGate::setMinfinity( const Eref& e, vector< double > val ) { - if ( val.size() != 5 ) { - cout << "Error: HHGate::setMinfinity on " << e.id().path() << - ": Number of entries on argument vector should be 5, was " << - val.size() << endl; - return; - } - if ( checkOriginal( e.id(), "mInfinity" ) ) { - mInfinity_ = val; - updateAlphaBeta(); - updateTables(); - } + if ( val.size() != 5 ) + { + cout << "Error: HHGate::setMinfinity on " << e.id().path() << + ": Number of entries on argument vector should be 5, was " << + val.size() << endl; + return; + } + if ( checkOriginal( e.id(), "mInfinity" ) ) + { + mInfinity_ = val; + updateAlphaBeta(); + updateTables(); + } } double HHGate::getMin( const Eref& e) const { - return xmin_; + return xmin_; } void HHGate::setMin( const Eref& e, double val ) { - if ( checkOriginal( e.id(), "min" ) ) { - xmin_ = val; - unsigned int xdivs = A_.size() - 1; - if ( isDirectTable_ && xdivs > 0 ) { - // Stuff here to stretch out table using interpolation. - invDx_ = static_cast< double >( xdivs ) / ( xmax_ - val ); - tabFill( A_, xdivs, val, xmax_ ); - tabFill( B_, xdivs, val, xmax_ ); - } else { - updateTables(); + if ( checkOriginal( e.id(), "min" ) ) + { + xmin_ = val; + unsigned int xdivs = A_.size() - 1; + if ( isDirectTable_ && xdivs > 0 ) + { + // Stuff here to stretch out table using interpolation. + invDx_ = static_cast< double >( xdivs ) / ( xmax_ - val ); + tabFill( A_, xdivs, val, xmax_ ); + tabFill( B_, xdivs, val, xmax_ ); + } + else + { + updateTables(); + } } - } } double HHGate::getMax( const Eref& e) const { - return xmax_; + return xmax_; } void HHGate::setMax( const Eref& e, double val ) { - if ( checkOriginal( e.id(), "max" ) ) { - xmax_ = val; - unsigned int xdivs = A_.size() - 1; - if ( isDirectTable_ && xdivs > 0 ) { - // Set up using direct assignment of table values. - invDx_ = static_cast< double >( xdivs ) / ( val - xmin_ ); - tabFill( A_, xdivs, xmin_, val ); - tabFill( B_, xdivs, xmin_, val ); - } else { - // Set up using functional form. here we just recalculate. - updateTables(); + if ( checkOriginal( e.id(), "max" ) ) + { + xmax_ = val; + unsigned int xdivs = A_.size() - 1; + if ( isDirectTable_ && xdivs > 0 ) + { + // Set up using direct assignment of table values. + invDx_ = static_cast< double >( xdivs ) / ( val - xmin_ ); + tabFill( A_, xdivs, xmin_, val ); + tabFill( B_, xdivs, xmin_, val ); + } + else + { + // Set up using functional form. here we just recalculate. + updateTables(); + } } - } } unsigned int HHGate::getDivs( const Eref& e) const { - return A_.size() - 1; + return A_.size() - 1; } void HHGate::setDivs( const Eref& e, unsigned int val ) { - if ( checkOriginal( e.id(), "divs" ) ) { - if ( isDirectTable_ ) { - invDx_ = static_cast< double >( val ) / ( xmax_ - xmin_ ); - tabFill( A_, val, xmin_, xmax_ ); - tabFill( B_, val, xmin_, xmax_ ); - } else { - /// Stuff here to redo sizes. - A_.resize( val + 1 ); - B_.resize( val + 1 ); - invDx_ = static_cast< double >( val ) / ( xmax_ - xmin_ ); - updateTables(); + if ( checkOriginal( e.id(), "divs" ) ) + { + if ( isDirectTable_ ) + { + invDx_ = static_cast< double >( val ) / ( xmax_ - xmin_ ); + tabFill( A_, val, xmin_, xmax_ ); + tabFill( B_, val, xmin_, xmax_ ); + } + else + { + /// Stuff here to redo sizes. + A_.resize( val + 1 ); + B_.resize( val + 1 ); + invDx_ = static_cast< double >( val ) / ( xmax_ - xmin_ ); + updateTables(); + } } - } } vector< double > HHGate::getTableA( const Eref& e) const { - return A_; + return A_; } void HHGate::setTableA( const Eref& e, vector< double > v ) { - if ( v.size() < 2 ) { - cout << "Warning: HHGate::setTableA: size must be >= 2 entries on " - << e.id().path() << endl; - return; - } - if ( checkOriginal( e.id(), "tableA" ) ) { - isDirectTable_ = 1; - A_ = v; - unsigned int xdivs = A_.size() - 1; - invDx_ = static_cast< double >( xdivs ) / ( xmax_ - xmin_ ); - } + if ( v.size() < 2 ) + { + cout << "Warning: HHGate::setTableA: size must be >= 2 entries on " + << e.id().path() << endl; + return; + } + if ( checkOriginal( e.id(), "tableA" ) ) + { + isDirectTable_ = 1; + A_ = v; + unsigned int xdivs = A_.size() - 1; + invDx_ = static_cast< double >( xdivs ) / ( xmax_ - xmin_ ); + } } vector< double > HHGate::getTableB( const Eref& e) const { - return B_; + return B_; } void HHGate::setTableB( const Eref& e, vector< double > v ) { - if ( checkOriginal( e.id(), "tableB" ) ) { - isDirectTable_ = 1; - if ( A_.size() != v.size() ) { - cout << "Warning: HHGate::setTableB: size should be same as table A: " << v.size() << " != " << A_.size() << ". Ignoring.\n"; - return; + if ( checkOriginal( e.id(), "tableB" ) ) + { + isDirectTable_ = 1; + if ( A_.size() != v.size() ) + { + cout << "Warning: HHGate::setTableB: size should be same as table A: " << v.size() << " != " << A_.size() << ". Ignoring.\n"; + return; + } + B_ = v; } - B_ = v; - } } bool HHGate::getUseInterpolation( const Eref& e) const { - return lookupByInterpolation_; + return lookupByInterpolation_; } void HHGate::setUseInterpolation( const Eref& e, bool val ) { - if ( checkOriginal( e.id(), "useInterpolation" ) ) - lookupByInterpolation_ = val; + if ( checkOriginal( e.id(), "useInterpolation" ) ) + lookupByInterpolation_ = val; } void HHGate::setupAlpha( const Eref& e, - vector< double > parms ) + vector< double > parms ) { - if ( checkOriginal( e.id(), "setupAlpha" ) ) { - if ( parms.size() != 13 ) { - cout << "HHGate::setupAlpha: Error: parms.size() != 13\n"; - return; + if ( checkOriginal( e.id(), "setupAlpha" ) ) + { + if ( parms.size() != 13 ) + { + cout << "HHGate::setupAlpha: Error: parms.size() != 13\n"; + return; + } + setupTables( parms, false ); + alpha_.resize( 5, 0 ); + beta_.resize( 5, 0 ); + for ( unsigned int i = 0; i < 5; ++i ) + alpha_[i] = parms[i]; + for ( unsigned int i = 5; i < 10; ++i ) + beta_[i - 5] = parms[i]; } - setupTables( parms, false ); - alpha_.resize( 5, 0 ); - beta_.resize( 5, 0 ); - for ( unsigned int i = 0; i < 5; ++i ) - alpha_[i] = parms[i]; - for ( unsigned int i = 5; i < 10; ++i ) - beta_[i - 5] = parms[i]; - } } vector< double > HHGate::getAlphaParms( const Eref& e ) const { - vector< double > ret = alpha_; - ret.insert( ret.end(), beta_.begin(), beta_.end() ); - ret.push_back( A_.size() ); - ret.push_back( xmin_ ); - ret.push_back( xmax_ ); + vector< double > ret = alpha_; + ret.insert( ret.end(), beta_.begin(), beta_.end() ); + ret.push_back( A_.size() ); + ret.push_back( xmin_ ); + ret.push_back( xmax_ ); - return ret; + return ret; } /////////////////////////////////////////////////// @@ -522,25 +559,27 @@ vector< double > HHGate::getAlphaParms( const Eref& e ) const /////////////////////////////////////////////////// void HHGate::setupTau( const Eref& e, - vector< double > parms ) + vector< double > parms ) { - if ( checkOriginal( e.id(), "setupTau" ) ) { - if ( parms.size() != 13 ) { - cout << "HHGate::setupTau: Error: parms.size() != 13\n"; - return; + if ( checkOriginal( e.id(), "setupTau" ) ) + { + if ( parms.size() != 13 ) + { + cout << "HHGate::setupTau: Error: parms.size() != 13\n"; + return; + } + setupTables( parms, true ); } - setupTables( parms, true ); - } } void HHGate::tweakAlpha() { - ; // Dummy + ; // Dummy } void HHGate::tweakTau() { - ; // Dummy + ; // Dummy } /** @@ -550,96 +589,114 @@ void HHGate::tweakTau() */ void HHGate::setupTables( const vector< double >& parms, bool doTau ) { - assert( parms.size() == 13 ); - static const int XDIVS = 10; - static const int XMIN = 11; - static const int XMAX = 12; - if ( parms[XDIVS] < 1 ) return; - unsigned int xdivs = static_cast< unsigned int >( parms[XDIVS] ); - - A_.resize( xdivs + 1 ); - B_.resize( xdivs + 1 ); - xmin_ = parms[XMIN]; - xmax_ = parms[XMAX]; - assert( xmax_ > xmin_ ); - invDx_ = xdivs / (xmax_ - xmin_ ); - double dx = ( xmax_ - xmin_ ) / xdivs; - - double x = xmin_; - double prevAentry = 0.0; - double prevBentry = 0.0; - double temp; - double temp2 = 0.0; - unsigned int i; - - for( i = 0; i <= xdivs; i++ ) { - if ( fabs( parms[4] ) < SINGULARITY ) { - temp = 0.0; - A_[i] = temp; - } else { - temp2 = parms[2] + exp( ( x + parms[3] ) / parms[4] ); - if ( fabs( temp2 ) < SINGULARITY ) { - temp2 = parms[2] + exp( ( x + dx/10.0 + parms[3] ) / parms[4] ); - temp = ( parms[0] + parms[1] * (x + dx/10 ) ) / temp2; - - temp2 = parms[2] + exp( ( x - dx/10.0 + parms[3] ) / parms[4] ); - temp += ( parms[0] + parms[1] * (x - dx/10 ) ) / temp2; - temp /= 2.0; - // cout << "interpolated temp = " << temp << ", prev = " << prevAentry << endl; - - // temp = prevAentry; - A_[i] = temp; - } else { - temp = ( parms[0] + parms[1] * x) / temp2; - A_[i] = temp; - } - } - if ( fabs( parms[9] ) < SINGULARITY ) { - B_[i] = 0.0; - } else { - temp2 = parms[7] + exp( ( x + parms[8] ) / parms[9] ); - if ( fabs( temp2 ) < SINGULARITY ) { - temp2 = parms[7] + exp( ( x + dx/10.0 + parms[8] ) / parms[9] ); - temp = (parms[5] + parms[6] * (x + dx/10) ) / temp2; - temp2 = parms[7] + exp( ( x - dx/10.0 + parms[8] ) / parms[9] ); - temp += (parms[5] + parms[6] * (x - dx/10) ) / temp2; - temp /= 2.0; - B_[i] = temp; - // B_[i] = prevBentry; - } else { - B_[i] = (parms[5] + parms[6] * x ) / temp2; - // B_.table_[i] = ( parms[5] + parms[6] * x ) / temp2; - } - } - // There are cleaner ways to do this, but this keeps - // the relation to the GENESIS version clearer. - // Note the additional SINGULARITY check, to fix a bug - // in the earlier code. - if ( doTau == 0 && fabs( temp2 ) > SINGULARITY ) - B_[i] += temp; - - prevAentry = A_[i]; - prevBentry = B_[i]; - x += dx; - } - - prevAentry = 0.0; - prevBentry = 0.0; - if ( doTau ) { - for( i = 0; i <= xdivs; i++ ) { - temp = A_[i]; - temp2 = B_[i]; - if ( fabs( temp ) < SINGULARITY ) { - A_[i] = prevAentry; - B_[i] = prevBentry; - } else { - A_[i] = temp2 / temp; - B_[i] = 1.0 / temp; - } - prevAentry = A_[i]; - prevBentry = B_[i]; - } - } + assert( parms.size() == 13 ); + static const int XDIVS = 10; + static const int XMIN = 11; + static const int XMAX = 12; + if ( parms[XDIVS] < 1 ) return; + unsigned int xdivs = static_cast< unsigned int >( parms[XDIVS] ); + + A_.resize( xdivs + 1 ); + B_.resize( xdivs + 1 ); + xmin_ = parms[XMIN]; + xmax_ = parms[XMAX]; + assert( xmax_ > xmin_ ); + invDx_ = xdivs / (xmax_ - xmin_ ); + double dx = ( xmax_ - xmin_ ) / xdivs; + + double x = xmin_; + double prevAentry = 0.0; + double prevBentry = 0.0; + double temp; + double temp2 = 0.0; + unsigned int i; + + for( i = 0; i <= xdivs; i++ ) + { + if ( fabs( parms[4] ) < SINGULARITY ) + { + temp = 0.0; + A_[i] = temp; + } + else + { + temp2 = parms[2] + exp( ( x + parms[3] ) / parms[4] ); + if ( fabs( temp2 ) < SINGULARITY ) + { + temp2 = parms[2] + exp( ( x + dx/10.0 + parms[3] ) / parms[4] ); + temp = ( parms[0] + parms[1] * (x + dx/10 ) ) / temp2; + + temp2 = parms[2] + exp( ( x - dx/10.0 + parms[3] ) / parms[4] ); + temp += ( parms[0] + parms[1] * (x - dx/10 ) ) / temp2; + temp /= 2.0; + // cout << "interpolated temp = " << temp << ", prev = " << prevAentry << endl; + + // temp = prevAentry; + A_[i] = temp; + } + else + { + temp = ( parms[0] + parms[1] * x) / temp2; + A_[i] = temp; + } + } + if ( fabs( parms[9] ) < SINGULARITY ) + { + B_[i] = 0.0; + } + else + { + temp2 = parms[7] + exp( ( x + parms[8] ) / parms[9] ); + if ( fabs( temp2 ) < SINGULARITY ) + { + temp2 = parms[7] + exp( ( x + dx/10.0 + parms[8] ) / parms[9] ); + temp = (parms[5] + parms[6] * (x + dx/10) ) / temp2; + temp2 = parms[7] + exp( ( x - dx/10.0 + parms[8] ) / parms[9] ); + temp += (parms[5] + parms[6] * (x - dx/10) ) / temp2; + temp /= 2.0; + B_[i] = temp; + // B_[i] = prevBentry; + } + else + { + B_[i] = (parms[5] + parms[6] * x ) / temp2; + // B_.table_[i] = ( parms[5] + parms[6] * x ) / temp2; + } + } + // There are cleaner ways to do this, but this keeps + // the relation to the GENESIS version clearer. + // Note the additional SINGULARITY check, to fix a bug + // in the earlier code. + if ( doTau == 0 && fabs( temp2 ) > SINGULARITY ) + B_[i] += temp; + + prevAentry = A_[i]; + prevBentry = B_[i]; + x += dx; + } + + prevAentry = 0.0; + prevBentry = 0.0; + if ( doTau ) + { + for( i = 0; i <= xdivs; i++ ) + { + temp = A_[i]; + temp2 = B_[i]; + if ( fabs( temp ) < SINGULARITY ) + { + A_[i] = prevAentry; + B_[i] = prevBentry; + } + else + { + A_[i] = temp2 / temp; + B_[i] = 1.0 / temp; + } + prevAentry = A_[i]; + prevBentry = B_[i]; + } + } } /** @@ -649,97 +706,116 @@ void HHGate::setupTables( const vector< double >& parms, bool doTau ) */ void HHGate::tweakTables( bool doTau ) { - unsigned int i; - unsigned int size = A_.size(); - assert( size == B_.size() ); - if ( doTau ) { - for ( i = 0; i < size; i++ ) { - double temp = A_[ i ]; - double temp2 = B_[ i ]; - if ( fabs( temp ) < SINGULARITY ) { - if ( temp < 0.0 ) - temp = -SINGULARITY; - else - temp = SINGULARITY; - } - A_[ i ] = temp2 / temp; - B_[ i ] = 1.0 / temp; - } - } else { - for ( i = 0; i < size; i++ ) - B_[i] = A_[i] + B_[i]; - } + unsigned int i; + unsigned int size = A_.size(); + assert( size == B_.size() ); + if ( doTau ) + { + for ( i = 0; i < size; i++ ) + { + double temp = A_[ i ]; + double temp2 = B_[ i ]; + if ( fabs( temp ) < SINGULARITY ) + { + if ( temp < 0.0 ) + temp = -SINGULARITY; + else + temp = SINGULARITY; + } + A_[ i ] = temp2 / temp; + B_[ i ] = 1.0 / temp; + } + } + else + { + for ( i = 0; i < size; i++ ) + B_[i] = A_[i] + B_[i]; + } } void HHGate::setupGate( const Eref& e, - vector< double > parms ) -{ - // The nine arguments are : - // A B C D F size min max isbeta - // If size == 0 then we check that the gate has already been allocated. - // If isbeta is true then we also have to do the conversion to - // HHGate form of alpha, alpha+beta, assuming that the alpha gate - // has already been setup. This uses tweakTables. - // We may need to resize the tables if they don't match here. - if ( !checkOriginal( e.id(), "setupGate" ) ) - return; - - if ( parms.size() != 9 ) { - cout << "HHGate::setupGate: Error: parms.size() != 9\n"; - return; - } - - double A = parms[0]; - double B = parms[1]; - double C = parms[2]; - double D = parms[3]; - double F = parms[4]; - int size = static_cast< int > (parms[5] ); - double min = parms[6]; - double max = parms[7]; - bool isBeta = static_cast< bool >( parms[8] ); - - vector< double >& ip = ( isBeta ) ? B_ : A_; - - if ( size <= 0 ) { // Look up size, min, max from the interpol - size = ip.size() - 1; - if ( size <= 0 ) { - cout << "Error: setupGate has zero size\n"; - return; - } - } else { - ip.resize( size + 1 ); - } - - double dx = ( max - min ) / static_cast< double >( size ); - double x = min + dx / 2.0; - for ( int i = 0; i <= size; i++ ) { - if ( fabs ( F ) < SINGULARITY ) { - ip[i] = 0.0; - } else { - double temp2 = C + exp( ( x + D ) / F ); - if ( fabs( temp2 ) < SINGULARITY ) - ip[i] = ip[i-1]; - else - ip[i] = ( A + B * x ) / temp2; - } - } - - if ( isBeta ) { - assert( A_.size() > 0 ); - // Here we ensure that the tables are the same size - if ( A_.size() != B_.size() ) { - if ( A_.size() > B_.size() ) { - // Note that the tabFill expects to allocate the - // terminating entry, so we put in size - 1. - tabFill( B_, A_.size() - 1, xmin_, xmax_ ); - } else { - tabFill( A_, B_.size() - 1, xmin_, xmax_ ); - } - } - // Then we do the tweaking to convert to HHChannel form. - tweakTables( 0 ); - } + vector< double > parms ) +{ + // The nine arguments are : + // A B C D F size min max isbeta + // If size == 0 then we check that the gate has already been allocated. + // If isbeta is true then we also have to do the conversion to + // HHGate form of alpha, alpha+beta, assuming that the alpha gate + // has already been setup. This uses tweakTables. + // We may need to resize the tables if they don't match here. + if ( !checkOriginal( e.id(), "setupGate" ) ) + return; + + if ( parms.size() != 9 ) + { + cout << "HHGate::setupGate: Error: parms.size() != 9\n"; + return; + } + + double A = parms[0]; + double B = parms[1]; + double C = parms[2]; + double D = parms[3]; + double F = parms[4]; + int size = static_cast< int > (parms[5] ); + double min = parms[6]; + double max = parms[7]; + bool isBeta = static_cast< bool >( parms[8] ); + + vector< double >& ip = ( isBeta ) ? B_ : A_; + + if ( size <= 0 ) // Look up size, min, max from the interpol + { + size = ip.size() - 1; + if ( size <= 0 ) + { + cout << "Error: setupGate has zero size\n"; + return; + } + } + else + { + ip.resize( size + 1 ); + } + + double dx = ( max - min ) / static_cast< double >( size ); + double x = min + dx / 2.0; + for ( int i = 0; i <= size; i++ ) + { + if ( fabs ( F ) < SINGULARITY ) + { + ip[i] = 0.0; + } + else + { + double temp2 = C + exp( ( x + D ) / F ); + if ( fabs( temp2 ) < SINGULARITY ) + ip[i] = ip[i-1]; + else + ip[i] = ( A + B * x ) / temp2; + } + } + + if ( isBeta ) + { + assert( A_.size() > 0 ); + // Here we ensure that the tables are the same size + if ( A_.size() != B_.size() ) + { + if ( A_.size() > B_.size() ) + { + // Note that the tabFill expects to allocate the + // terminating entry, so we put in size - 1. + tabFill( B_, A_.size() - 1, xmin_, xmax_ ); + } + else + { + tabFill( A_, B_.size() - 1, xmin_, xmax_ ); + } + } + // Then we do the tweaking to convert to HHChannel form. + tweakTables( 0 ); + } } /////////////////////////////////////////////////////////////////////// @@ -753,54 +829,56 @@ void HHGate::setupGate( const Eref& e, * subdivisions that the table represents. */ void HHGate::tabFill( vector< double >& table, - unsigned int newXdivs, double newXmin, double newXmax ) + unsigned int newXdivs, double newXmin, double newXmax ) { - if ( newXdivs < 3 ) { - cout << "Error: tabFill: # divs must be >= 3. Not filling table.\n"; - return; - } + if ( newXdivs < 3 ) + { + cout << "Error: tabFill: # divs must be >= 3. Not filling table.\n"; + return; + } - vector< double > old = table; - double newDx = ( newXmax - newXmin ) / newXdivs; - table.resize( newXdivs + 1 ); - bool origLookupMode = lookupByInterpolation_; - lookupByInterpolation_ = 1; + vector< double > old = table; + double newDx = ( newXmax - newXmin ) / newXdivs; + table.resize( newXdivs + 1 ); + bool origLookupMode = lookupByInterpolation_; + lookupByInterpolation_ = 1; - for( unsigned int i = 0; i <= newXdivs; ++i ) { - table[i] = lookupTable( table, newXmin + i * newDx ); - } + for( unsigned int i = 0; i <= newXdivs; ++i ) + { + table[i] = lookupTable( table, newXmin + i * newDx ); + } - lookupByInterpolation_ = origLookupMode; + lookupByInterpolation_ = origLookupMode; } bool HHGate::checkOriginal( Id id, const string& field ) const { - if ( id == originalGateId_ ) - return 1; + if ( id == originalGateId_ ) + return 1; - cout << "Warning: HHGate: attempt to set field '" << field << "' on " << - id.path() << "\nwhich is not the original Gate element. Ignored.\n"; - return 0; + cout << "Warning: HHGate: attempt to set field '" << field << "' on " << + id.path() << "\nwhich is not the original Gate element. Ignored.\n"; + return 0; } bool HHGate::isOriginalChannel( Id id ) const { - return ( id == originalChanId_ ); + return ( id == originalChanId_ ); } bool HHGate::isOriginalGate( Id id ) const { - return ( id == originalGateId_ ); + return ( id == originalGateId_ ); } Id HHGate::originalChannelId() const { - return originalChanId_; + return originalChanId_; } Id HHGate::originalGateId() const { - return originalGateId_; + return originalGateId_; } void HHGate::updateAlphaBeta() @@ -813,13 +891,13 @@ void HHGate::updateTauMinf() void HHGate::updateTables() { - if ( alpha_.size() == 0 || beta_.size() == 0 ) - return; - vector< double > parms = alpha_; - parms.insert( parms.end(), beta_.begin(), beta_.end() ); - parms.push_back( A_.size() ); - parms.push_back( xmin_ ); - parms.push_back( xmax_ ); + if ( alpha_.size() == 0 || beta_.size() == 0 ) + return; + vector< double > parms = alpha_; + parms.insert( parms.end(), beta_.begin(), beta_.end() ); + parms.push_back( A_.size() ); + parms.push_back( xmin_ ); + parms.push_back( xmax_ ); - setupTables( parms, 0 ); + setupTables( parms, 0 ); } diff --git a/biophysics/HHGate.h b/biophysics/HHGate.h index a5c79eb5..eadb2821 100644 --- a/biophysics/HHGate.h +++ b/biophysics/HHGate.h @@ -28,6 +28,7 @@ * Field assignment to the HHGate should be possible only from the * original HHChannel, but all the others do have read permission. */ + class HHGate { friend void testHHGateLookup(); @@ -100,12 +101,10 @@ class HHGate ////////////////////////////////////////////////////////// // DestFinfos ////////////////////////////////////////////////////////// - void setupTau( const Eref& e, - vector< double > parms ); + void setupTau( const Eref& e, vector< double > parms ); void tweakAlpha(); void tweakTau(); - void setupGate( const Eref& e, - vector< double > parms ); + void setupGate( const Eref& e, vector< double > parms ); void setupTables( const vector< double >& parms, bool doTau ); void tweakTables( bool doTau ); diff --git a/biophysics/Neuron.cpp b/biophysics/Neuron.cpp index 15ec8e60..4d5993f1 100644 --- a/biophysics/Neuron.cpp +++ b/biophysics/Neuron.cpp @@ -1141,10 +1141,29 @@ void Neuron::setChannelDistribution( const Eref& e, vector< string > v ) vector< vector< string > > lines; if ( parseDistrib( lines, v ) ) { + unsigned int index = 0; + vector< unsigned int > chanIndices; + vector< unsigned int > temp; channelDistribution_ = v; + // We need to ensure that Ca_concs are created before any channels + // since the channels may want to connect to them. for ( unsigned int i = 0; i < lines.size(); ++i ) { - vector< string >& temp = lines[i]; + Id proto( "/library/" + lines[i][0] ); + if ( proto != Id() ) { + if ( proto.element()->cinfo()->isA( "CaConcBase" ) ) { + chanIndices.push_back( i ); + } else { + temp.push_back( i ); + } + } + } + chanIndices.insert( chanIndices.end(), temp.begin(), temp.end() ); + assert( chanIndices.size() == lines.size() ); + + for ( unsigned int i = 0; i < lines.size(); ++i ) + { + vector< string >& temp = lines[chanIndices[i]]; vector< ObjId > elist; vector< double > val; buildElist( e, temp, elist, val ); diff --git a/builtins/CMakeLists.txt b/builtins/CMakeLists.txt index 9c226011..3df4cd96 100644 --- a/builtins/CMakeLists.txt +++ b/builtins/CMakeLists.txt @@ -19,6 +19,7 @@ set(SRCS Stats.cpp Interpol2D.cpp SpikeStats.cpp + SocketStreamer.cpp testBuiltins.cpp ) diff --git a/builtins/SocketStreamer.cpp b/builtins/SocketStreamer.cpp new file mode 100644 index 00000000..e3097f08 --- /dev/null +++ b/builtins/SocketStreamer.cpp @@ -0,0 +1,591 @@ +/*** + * Filename: SocketStreamer.cpp + * + * Description: TCP and Unix Domain Socket to stream data. + * + * Author: Dilawar Singh <dilawar.s.rajput@gmail.com> + * Organization: NCBS Bangalore + * + * License: See MOOSE licence. + */ + +#include <algorithm> +#include <sstream> +#include <chrono> +#include <thread> +#include <unistd.h> + +#include "../basecode/global.h" +#include "../basecode/header.h" +#include "../scheduling/Clock.h" +#include "../utility/utility.h" +#include "../shell/Shell.h" +#include "SocketStreamer.h" + +const Cinfo* SocketStreamer::initCinfo() +{ + /*----------------------------------------------------------------------------- + * Finfos + *-----------------------------------------------------------------------------*/ + static ValueFinfo< SocketStreamer, size_t > port( + "port" + , "Set port number for streaming. Valid only of TCP socket." + , &SocketStreamer::setPort + , &SocketStreamer::getPort + ); + + static ValueFinfo< SocketStreamer, string > address( + "address" + , "Set adresss for socket e.g. http://localhost:31416 (host:port for TCP SOCKET) " + ", or file:///tmp/MOOSE_SOCK for UNIX domain socket." + , &SocketStreamer::setAddress + , &SocketStreamer::getAddress + ); + + static ReadOnlyValueFinfo< SocketStreamer, size_t > numTables ( + "numTables" + , "Number of Tables handled by SocketStreamer " + , &SocketStreamer::getNumTables + ); + + /*----------------------------------------------------------------------------- + * + *-----------------------------------------------------------------------------*/ + static DestFinfo process( + "process" + , "Handle process call" + , new ProcOpFunc<SocketStreamer>(&SocketStreamer::process) + ); + + static DestFinfo reinit( + "reinit" + , "Handles reinit call" + , new ProcOpFunc<SocketStreamer> (&SocketStreamer::reinit) + ); + + static DestFinfo addTable( + "addTable" + , "Add a table to SocketStreamer" + , new OpFunc1<SocketStreamer, Id>(&SocketStreamer::addTable) + ); + + static DestFinfo addTables( + "addTables" + , "Add many tables to SocketStreamer" + , new OpFunc1<SocketStreamer, vector<Id> >(&SocketStreamer::addTables) + ); + + static DestFinfo removeTable( + "removeTable" + , "Remove a table from SocketStreamer" + , new OpFunc1<SocketStreamer, Id>(&SocketStreamer::removeTable) + ); + + static DestFinfo removeTables( + "removeTables" + , "Remove tables -- if found -- from SocketStreamer" + , new OpFunc1<SocketStreamer, vector<Id>>(&SocketStreamer::removeTables) + ); + + /*----------------------------------------------------------------------------- + * ShareMsg definitions. + *-----------------------------------------------------------------------------*/ + static Finfo* procShared[] = + { + &process, &reinit, &addTable, &addTables, &removeTable, &removeTables + }; + + static SharedFinfo proc( + "proc", + "Shared message for process and reinit", + procShared, sizeof( procShared ) / sizeof( const Finfo* ) + ); + + static Finfo * socketStreamFinfo[] = + { + &port, &address, &proc, &numTables + }; + + static string doc[] = + { + "Name", "SocketStreamer", + "Author", "Dilawar Singh (@dilawar, github), 2018", + "Description", "SocketStreamer: Stream moose.Table data to a socket.\n" + }; + + static Dinfo< SocketStreamer > dinfo; + + static Cinfo tableStreamCinfo( + "SocketStreamer", + TableBase::initCinfo(), + socketStreamFinfo, + sizeof( socketStreamFinfo )/sizeof(Finfo *), + &dinfo, + doc, + sizeof(doc) / sizeof(string) + ); + + return &tableStreamCinfo; +} + +static const Cinfo* tableStreamCinfo = SocketStreamer::initCinfo(); + +// Constructor +SocketStreamer::SocketStreamer() : + currTime_(0.0) + , numMaxClients_(1) + , sockType_ ( UNIX_DOMAIN_SOCKET ) + , sockfd_(-1) + , clientfd_(-1) + , ip_( TCP_SOCKET_IP ) + , port_( TCP_SOCKET_PORT ) + , address_ ( "file://MOOSE" ) +{ + clk_ = reinterpret_cast<Clock*>( Id(1).eref().data() ); + + // Not all compilers allow initialization during the declaration of class + // methods. + columns_.push_back( "time" ); /* First column is time. */ + tables_.resize(0); + tableIds_.resize(0); + tableTick_.resize(0); + tableDt_.resize(0); + +} + +SocketStreamer& SocketStreamer::operator=( const SocketStreamer& st ) +{ + return *this; +} + + +// Deconstructor +SocketStreamer::~SocketStreamer() +{ + // Now cleanup the socket as well. + all_done_ = true; + if(sockfd_ > 0) + { + LOG(moose::debug, "Closing socket " << sockfd_ ); + shutdown(sockfd_, SHUT_RD); + close(sockfd_); + + if( sockType_ == UNIX_DOMAIN_SOCKET ) + ::unlink( unixSocketFilePath_.c_str() ); + } + + if( processThread_.joinable() ) + processThread_.join(); +} + +/* --------------------------------------------------------------------------*/ +/** + * @Synopsis Stop a thread. + * See: http://www.bo-yang.net/2017/11/19/cpp-kill-detached-thread + * + * @Param tname name of thread. + */ +/* ----------------------------------------------------------------------------*/ +//void SocketStreamer::stopThread(const std::string& tname) +//{ +// ThreadMap::const_iterator it = tm_.find(tname); +// if (it != tm_.end()) +// { +// it->second.std::thread::~thread(); // thread not killed +// tm_.erase(tname); +// LOG(moose::debug, "Thread " << tname << " killed." ); +// } +//} + + +/* --------------------------------------------------------------------------*/ +/** + * @Synopsis Connect to a client. If already connected to one, then do not make + * any more connections. + */ +/* ----------------------------------------------------------------------------*/ +void SocketStreamer::listenToClients(size_t numMaxClients) +{ + assert(0 < sockfd_ ); + assert( numMaxClients > 0 ); + numMaxClients_ = numMaxClients; + if(-1 == listen(sockfd_, numMaxClients_)) + LOG(moose::error, "Failed listen() on socket " << sockfd_ + << ". Error was: " << strerror(errno) ); + +} + +void SocketStreamer::initServer( void ) +{ + setSocketType( ); + if( sockType_ == UNIX_DOMAIN_SOCKET ) + initUDSServer(); + else + initTCPServer(); + + LOG(moose::debug, "Successfully created SocketStreamer server: " << sockfd_); + + // Listen for incoming clients. This function does nothing if connection is + // already made. + listenToClients(2); +} + +void SocketStreamer::configureSocketServer( ) +{ + // One can set socket option using setsockopt function. See manual page + // for details. We are making it 'reusable'. + int on = 1; + +#ifdef SO_REUSEADDR + if(0 > setsockopt(sockfd_, SOL_SOCKET, SO_REUSEPORT, (const char *)&on, sizeof(on))) + LOG(moose::warning, "Warn: setsockopt() failed"); +#endif + + if(0 > setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on))) + LOG(moose::warning, "Warn: setsockopt() failed"); +} + +void SocketStreamer::initUDSServer( void ) +{ + // PF_UNIX means that sockets are local. + sockfd_ = socket(PF_UNIX, SOCK_STREAM, 0); + if( ! sockfd_) + { + isValid_ = false; + perror( "Socket" ); + } + + if( sockfd_ > 0 ) + { + unixSocketFilePath_ = address_.substr(7); bzero(&sockAddrUDS_, sizeof(sockAddrUDS_)); + sockAddrUDS_.sun_family = AF_UNIX; + strncpy(sockAddrUDS_.sun_path, unixSocketFilePath_.c_str(), sizeof(sockAddrUDS_.sun_path)-1); + configureSocketServer(); + + // Bind. Make sure bind is not std::bind + if(0 > ::bind(sockfd_, (struct sockaddr*) &sockAddrUDS_, sizeof(sockAddrUDS_))) + { + isValid_ = false; + LOG(moose::warning, "Warn: Failed to create socket at " << unixSocketFilePath_ + << ". File descriptor: " << sockfd_ + << ". Erorr: " << strerror(errno) + ); + } + } + + if( (! isValid_) || (sockfd_ < 0) ) + ::unlink( unixSocketFilePath_.c_str() ); +} + +void SocketStreamer::initTCPServer( void ) +{ + // Create a blocking socket. + LOG( moose::debug, "Creating TCP socket on port: " << port_ ); + sockfd_ = socket(AF_INET, SOCK_STREAM, 0); + if( 0 > sockfd_ ) + { + perror("socket"); + isValid_ = false; + return; + } + + configureSocketServer(); + bzero((char*) &sockAddrTCP_, sizeof(sockAddrTCP_)); + sockAddrTCP_.sin_family = AF_INET; + sockAddrTCP_.sin_addr.s_addr = INADDR_ANY; + sockAddrTCP_.sin_port = htons( port_ ); + + // Bind. Make sure bind is not std::bind + if(0 > ::bind(sockfd_, (struct sockaddr*) &sockAddrTCP_, sizeof(sockAddrTCP_))) + { + isValid_ = false; + LOG(moose::warning, "Warn: Failed to create server at " << ip_ << ":" << port_ + << ". File descriptor: " << sockfd_ + << ". Erorr: " << strerror(errno) + ); + return; + } +} + + +/* --------------------------------------------------------------------------*/ +/** + * @Synopsis Stream data over socket. + * + * @Returns True of success, false otherwise. It is callee job to clean up data_ + * on a successful return from this function. + */ +/* ----------------------------------------------------------------------------*/ +bool SocketStreamer::streamData( ) +{ + if( clientfd_ > 0) + { + buffer_ += dataToString(); + + if( buffer_.size() < frameSize_ ) + buffer_ += string(frameSize_-buffer_.size(), ' '); + + string toSend = buffer_.substr(0, frameSize_); + + int sent = send(clientfd_, buffer_.substr(0, frameSize_).c_str(), frameSize_, MSG_MORE); + buffer_ = buffer_.erase(0, sent); + + assert( sent == (int)frameSize_); + LOG(moose::debug, "Sent " << sent << " bytes." ); + + if(0 > sent) + { + LOG(moose::warning, "Failed to send. Error: " << strerror(errno) + << ". client id: " << clientfd_ ); + return false; + } + + // clear up the tables. + for( auto t : tables_ ) + t->clearVec(); + return true; + } + else + LOG(moose::warning, "No client found to stream data. ClientFD: " << clientfd_ ); + + return false; +} + +/* --------------------------------------------------------------------------*/ +/** + * @Synopsis Convert table to string (use scientific notation). + * + * @Returns String in JSON like format. + */ +/* ----------------------------------------------------------------------------*/ +string SocketStreamer::dataToString( ) +{ + stringstream ss; + // Enabling this would be require quite a lot of characters to be streamed. + //ss.precision( 7 ); + //ss << std::scientific; + vector<double> data; + + // Else stream the data. + ss << "{"; + for( size_t i = 0; i < tables_.size(); i++) + { + ss << "\"" << columns_[i+1] << "\":["; + ss << tables_[i]->toJSON(true); + ss << "],"; + } + + // remove , at the end else it won't be a valid JSON. + string res = ss.str(); + if( ',' == res.back()) + res.pop_back(); + res += "}\n"; + return res; +} + +bool SocketStreamer::enoughDataToStream(size_t minsize) +{ + for( size_t i = 0; i < tables_.size(); i++) + if(tables_[i]->getVec().size() >= minsize ) + return true; + return false; +} + +void SocketStreamer::connectAndStream( ) +{ + currTime_ = clk_->getCurrentTime(); + + // If server was invalid then there is no point. + if( ! isValid_ ) + { + LOG( moose::error, "Server could not set up." ); + return; + } + + // Now lets get into a loop to stream data. + while( (! all_done_) ) + { + clientfd_ = ::accept(sockfd_, NULL, NULL); + if( clientfd_ >= 0 ) + streamData(); + } +} + +/** + * @brief Reinit. We make sure it is non-blocking. + * + * @param e + * @param p + */ +void SocketStreamer::reinit(const Eref& e, ProcPtr p) +{ + if( tables_.size() == 0 ) + { + moose::showWarn( "No table found. Disabling SocketStreamer.\nDid you forget" + " to call addTables() on SocketStreamer object. " + e.objId().path() + ); + e.element()->setTick( -2 ); /* Disable process */ + return; + } + + thisDt_ = clk_->getTickDt( e.element()->getTick() ); + + // Push each table dt_ into vector of dt + for( size_t i = 0; i < tables_.size(); i++) + { + Id tId = tableIds_[i]; + int tickNum = tId.element()->getTick(); + tableDt_.push_back( clk_->getTickDt( tickNum ) ); + } + + // This should only be called once. + initServer(); + + // Launch a thread in background which monitors the any client trying to + // make connection to server. + processThread_ = std::thread(&SocketStreamer::connectAndStream, this); +} + +/** + * @brief This function is called at its clock tick. + * + * @param e + * @param p + */ +void SocketStreamer::process(const Eref& e, ProcPtr p) +{ + // It does nothing. See the connectAndStream function. + ; +} + +/** + * @brief Add a table to streamer. + * + * @param table Id of table. + */ +void SocketStreamer::addTable( Id table ) +{ + // If this table is not already in the vector, add it. + for( size_t i = 0; i < tableIds_.size(); i++) + if( table.path() == tableIds_[i].path() ) + return; /* Already added. */ + + Table* t = reinterpret_cast<Table*>(table.eref().data()); + tableIds_.push_back( table ); + tables_.push_back( t ); + tableTick_.push_back( table.element()->getTick() ); + + // NOTE: If user can make sure that names are unique in table, using name is + // better than using the full path. + if( t->getColumnName().size() > 0 ) + columns_.push_back( t->getColumnName( ) ); + else + columns_.push_back( moose::moosePathToUserPath( table.path() ) ); +} + +/** + * @brief Add multiple tables to SocketStreamer. + * + * @param tables + */ +void SocketStreamer::addTables( vector<Id> tables ) +{ + if( tables.size() == 0 ) + return; + for( vector<Id>::const_iterator it = tables.begin(); it != tables.end(); it++) + addTable( *it ); +} + +void SocketStreamer::addTables( vector<ObjId> tables ) +{ + if( tables.size() == 0 ) + return; + for( auto t : tables ) + addTable( Id(t) ); +} + + +/** + * @brief Remove a table from SocketStreamer. + * + * @param table. Id of table. + */ +void SocketStreamer::removeTable( Id table ) +{ + int matchIndex = -1; + for (size_t i = 0; i < tableIds_.size(); i++) + { + if( table.path() == tableIds_[i].path() ) + { + matchIndex = i; + break; + } + } + + if( matchIndex > -1 ) + { + tableIds_.erase( tableIds_.begin() + matchIndex ); + tables_.erase( tables_.begin() + matchIndex ); + columns_.erase( columns_.begin() + matchIndex ); + } +} + +/* --------------------------------------------------------------------------*/ +/** + * @Synopsis Determines socket type from the given address. + */ +/* ----------------------------------------------------------------------------*/ +void SocketStreamer::setSocketType( ) +{ + LOG( moose::debug, "Socket address is " << address_ ); + if( "file://" == address_.substr(0, 7)) + sockType_ = UNIX_DOMAIN_SOCKET; + else if( "http://" == address_.substr(0,7)) + sockType_ = TCP_SOCKET; + else + sockType_ = UNIX_DOMAIN_SOCKET; + return; +} + +/** + * @brief Remove multiple tables -- if found -- from SocketStreamer. + * + * @param tables + */ +void SocketStreamer::removeTables( vector<Id> tables ) +{ + for( vector<Id>::const_iterator it = tables.begin(); it != tables.end(); it++) + removeTable( *it ); +} + +/** + * @brief Get the number of tables handled by SocketStreamer. + * + * @return Number of tables. + */ +size_t SocketStreamer::getNumTables( void ) const +{ + return tables_.size(); +} + + +void SocketStreamer::setPort( const size_t port ) +{ + port_ = port; +} + +size_t SocketStreamer::getPort( void ) const +{ + assert( port_ > 1 ); + return port_; +} + +void SocketStreamer::setAddress( const string addr ) +{ + address_ = addr; +} + +string SocketStreamer::getAddress( void ) const +{ + return address_; +} diff --git a/builtins/SocketStreamer.h b/builtins/SocketStreamer.h new file mode 100644 index 00000000..c52bb7dd --- /dev/null +++ b/builtins/SocketStreamer.h @@ -0,0 +1,164 @@ +/*** + * Stream table data to a TCP socket. + */ + +#ifndef SocketStreamer_INC +#define SocketStreamer_INC + +#define STRINGSTREAM_DOUBLE_PRECISION 10 + +#include <iostream> +#include <string> +#include <map> +#include <fstream> +#include <sstream> +#include <thread> +#include <atomic> + +#include "StreamerBase.h" +#include "Table.h" + +// If cmake does not set it, use the default port. +#ifndef TCP_SOCKET_PORT +#define TCP_SOCKET_PORT 31416 +#endif + +#ifndef TCP_SOCKET_IP +#define TCP_SOCKET_IP "127.0.0.1" +#endif + +// Before send() can be used with c++. +#define _XOPEN_SOURCE_EXTENDED 1 + +// cmake should set include path. +#include <sys/socket.h> +#include <sys/poll.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/un.h> +#include <netinet/in.h> + +// MSG_MORE is not defined in OSX. So stupid! +#ifndef MSG_MORE +#define MSG_MORE 0 +#endif + +using namespace std; + +typedef enum t_socket_type_ {TCP_SOCKET, UNIX_DOMAIN_SOCKET} SocketType; // Type of socket. + +class Clock; + +class SocketStreamer : public StreamerBase +{ + +public: + SocketStreamer(); + ~SocketStreamer(); + + SocketStreamer& operator=( const SocketStreamer& st ); + + string getFormat( void ) const; + void setFormat( string format ); + + /*----------------------------------------------------------------------------- + * Socket Server + *-----------------------------------------------------------------------------*/ + // Initialize server. + void initServer( void ); + void initTCPServer( void ); + void initUDSServer( void ); + + /* common configuration options */ + void configureSocketServer( void ); + + // Make connection to client + void listenToClients(size_t numMaxClients); + + /* Cleaup before quitting */ + void cleanUp( void ); + + string getAddress( void ) const; + void setAddress( const string addr ); + + size_t getPort( void ) const; + void setPort( const size_t port ); + + SocketType getSocketType( ); + void setSocketType(void); + + /*----------------------------------------------------------------------------- + * Streaming data. + *-----------------------------------------------------------------------------*/ + bool enoughDataToStream(size_t minsize=10); + bool streamData(); + void connectAndStream( ); + + size_t getNumTables( void ) const; + + void addTable( Id table ); + void addTables( vector<Id> tables); + void addTables( vector<ObjId> tables); + + void removeTable( Id table ); + void removeTables( vector<Id> table ); + + string dataToString(); + + // void stopThread(const std::string& tname); + + /** Dest functions. + * The process function called by scheduler on every tick + */ + void process(const Eref& e, ProcPtr p); + + /** + * The reinit function called by scheduler for the reset + */ + void reinit(const Eref& e, ProcPtr p); + + static const Cinfo * initCinfo(); + +private: + + // dt_ and tick number of Table's clock + vector<double> tableDt_; + vector<unsigned int> tableTick_; + double currTime_; + + // Used for adding or removing tables + vector<Id> tableIds_; + vector<Table*> tables_; + vector<string> columns_; + + /* Socket related */ + int numMaxClients_; + SocketType sockType_ = UNIX_DOMAIN_SOCKET; // Default is UNIX_DOMAIN_SOCKET + int sockfd_; // socket file descriptor. + int clientfd_; // client file descriptor + + // TCP socket. + string ip_; // ip_ address of server. + unsigned short port_; // port number if socket is TCP_SOCKET + string address_; // adress of socket. Specified by user. + string unixSocketFilePath_; + + // address holdder for TCP and UDS sockets. + struct sockaddr_in sockAddrTCP_; + struct sockaddr_un sockAddrUDS_; + + /* For data handling */ + bool all_done_ = false; + bool isValid_ = true; + std::thread processThread_; + string buffer_; + double thisDt_; + + size_t frameSize_ = 2048; + + // We need clk_ pointer for handling + Clock* clk_ = nullptr; + +}; + +#endif /* ----- #ifndef SocketStreamer_INC ----- */ diff --git a/builtins/Streamer.cpp b/builtins/Streamer.cpp index 5ecde621..c583be1f 100644 --- a/builtins/Streamer.cpp +++ b/builtins/Streamer.cpp @@ -201,7 +201,7 @@ void Streamer::reinit(const Eref& e, ProcPtr p) { Id tId = tableIds_[i]; int tickNum = tId.element()->getTick(); - tableDt_.push_back( clk->getTickDt( tickNum ) ); + tableDt_.push_back( clk->getTickDt(tickNum) ); } // Make sure all tables have same dt_ else disable the streamer. diff --git a/builtins/StreamerBase.cpp b/builtins/StreamerBase.cpp index cb436b99..e6d590be 100644 --- a/builtins/StreamerBase.cpp +++ b/builtins/StreamerBase.cpp @@ -78,7 +78,6 @@ void StreamerBase::writeToOutFile( const string& filepath } } - /* Write to a csv file. */ void StreamerBase::writeToCSVFile( const string& filepath, const string& openmode , const vector<double>& data, const vector<string>& columns ) @@ -123,3 +122,10 @@ void StreamerBase::writeToNPYFile( const string& filepath, const string& openmod cnpy2::save_numpy<double>( filepath, data, columns, openmode ); } +string StreamerBase::vectorToCSV( const vector<double>& ys, const string& fmt ) +{ + stringstream ss; + for( auto v : ys ) + ss << v << ","; + return ss.str(); +} diff --git a/builtins/StreamerBase.h b/builtins/StreamerBase.h index c23dd500..b3e035b1 100644 --- a/builtins/StreamerBase.h +++ b/builtins/StreamerBase.h @@ -86,6 +86,17 @@ public: ); + /* --------------------------------------------------------------------------*/ + /** + * @Synopsis Return a csv representation of a vector. + * + * @Param ys vector of double. + * + * @Returns CSV string. + */ + /* ----------------------------------------------------------------------------*/ + string vectorToCSV( const vector<double>& ys, const string& fmt ); + private: string outfilePath_; diff --git a/builtins/Table.cpp b/builtins/Table.cpp index f5a6b771..4f426b14 100644 --- a/builtins/Table.cpp +++ b/builtins/Table.cpp @@ -210,12 +210,12 @@ const Cinfo* Table::initCinfo() static const Cinfo* tableCinfo = Table::initCinfo(); -Table::Table() : - threshold_( 0.0 ) , - lastTime_( 0.0 ) , - input_( 0.0 ), - fired_(false), - useSpikeMode_(false), +Table::Table() : + threshold_( 0.0 ) , + lastTime_( 0.0 ) , + input_( 0.0 ), + fired_(false), + useSpikeMode_(false), dt_( 0.0 ) { // Initialize the directory to which each table should stream. @@ -230,10 +230,9 @@ Table::~Table( ) // Make sure to write to rest of the entries to file before closing down. if( useStreamer_ ) { - zipWithTime( vec(), data_, lastTime_ ); + mergeWithTime( data_ ); StreamerBase::writeToOutFile( outfile_, format_, "a", data_, columns_ ); - clearVec(); - data_.clear(); + clearAllVecs(); } } @@ -250,17 +249,19 @@ Table& Table::operator=( const Table& tab ) void Table::process( const Eref& e, ProcPtr p ) { lastTime_ = p->currTime; + tvec_.push_back(lastTime_); // Copy incoming data to ret and insert into vector. vector< double > ret; requestOut()->send( e, &ret ); - if (useSpikeMode_) { - for ( vector< double >::const_iterator - i = ret.begin(); i != ret.end(); ++i ) - spike( *i ); - } else { - vec().insert( vec().end(), ret.begin(), ret.end() ); - } + + if (useSpikeMode_) + { + for ( vector< double >::const_iterator i = ret.begin(); i != ret.end(); ++i ) + spike( *i ); + } + else + vec().insert( vec().end(), ret.begin(), ret.end() ); /* If we are streaming to a file, let's write to a file. And clean the * vector. @@ -270,14 +271,20 @@ void Table::process( const Eref& e, ProcPtr p ) { if( fmod(lastTime_, 5.0) == 0.0 or getVecSize() >= 10000 ) { - zipWithTime( vec(), data_, lastTime_ ); + mergeWithTime( data_ ); StreamerBase::writeToOutFile( outfile_, format_ , "a", data_, columns_ ); - data_.clear(); - clearVec(); + clearAllVecs(); } } } +void Table::clearAllVecs() +{ + clearVec(); + tvec_.clear(); + data_.clear(); +} + /** * @brief Reinitialize * @@ -313,21 +320,22 @@ void Table::reinit( const Eref& e, ProcPtr p ) lastTime_ = 0; vector< double > ret; requestOut()->send( e, &ret ); - if (useSpikeMode_) { - for ( vector< double >::const_iterator - i = ret.begin(); i != ret.end(); ++i ) - spike( *i ); - } else { - vec().insert( vec().end(), ret.begin(), ret.end() ); - } + + if (useSpikeMode_) + { + for (vector<double>::const_iterator i = ret.begin(); i != ret.end(); ++i ) + spike( *i ); + } + else + vec().insert( vec().end(), ret.begin(), ret.end() ); + + tvec_.push_back(lastTime_); if( useStreamer_ ) { - zipWithTime( vec(), data_, lastTime_ ); + mergeWithTime( data_ ); StreamerBase::writeToOutFile( outfile_, format_, "w", data_, columns_); - clearVec(); - data_.clear(); - clearVec(); + clearAllVecs(); } } @@ -342,15 +350,20 @@ void Table::input( double v ) void Table::spike( double v ) { - if ( fired_ ) { // Wait for it to go below threshold - if ( v < threshold_ ) - fired_ = false; - } else { - if ( v > threshold_ ) { // wait for it to go above threshold. - fired_ = true; - vec().push_back( lastTime_ ); - } - } + if ( fired_ ) + { // Wait for it to go below threshold + if ( v < threshold_ ) + fired_ = false; + } + else + { + if ( v > threshold_ ) + { + // wait for it to go above threshold. + fired_ = true; + vec().push_back( lastTime_ ); + } + } } ////////////////////////////////////////////////////////////// @@ -450,15 +463,39 @@ double Table::getDt( void ) const * @brief Take the vector from table and timestamp it. It must only be called * when packing the data for writing. */ -void Table::zipWithTime( const vector<double>& v - , vector<double>& tvec - , const double& currTime - ) +void Table::mergeWithTime( vector<double>& data ) +{ + auto v = vec(); + for (size_t i = 0; i < v.size(); i++) + { + data.push_back(tvec_[i]); + data.push_back(v[i]); + } +} + +/* --------------------------------------------------------------------------*/ +/** + * @Synopsis. Convert table data to JOSN. + * + * @Param t. Upto this time. + * @Param withTime. Zip with time. + * + * @Returns string. + */ +/* ----------------------------------------------------------------------------*/ +string Table::toJSON( bool withTime) { - size_t N = v.size(); - for (size_t i = 0; i < N; i++) + auto v = vec(); + stringstream ss; + for (size_t i = 0; i < v.size(); i++) { - tvec.push_back( currTime - (N - i - 1 ) * dt_ ); - tvec.push_back( v[i] ); + if(withTime) + ss << '[' << tvec_[i] << ',' << v[i] << "],"; + else + ss << v[i] << ','; } + string res = ss.str(); + if( ',' == res.back()) + res.pop_back(); + return res; } diff --git a/builtins/Table.h b/builtins/Table.h index 34397cde..b3a0293b 100644 --- a/builtins/Table.h +++ b/builtins/Table.h @@ -48,11 +48,12 @@ public: // Access the dt_ of table. double getDt ( void ) const; - void zipWithTime ( - const vector<double>& yvec - , vector<double>& tvec - , const double& lasttime - ); + // merge time value among values. e.g. t1, v1, t2, v2, etc. + void mergeWithTime( vector<double>& data ); + + string toJSON(bool withTime=true); + + void clearAllVecs(); ////////////////////////////////////////////////////////////////// // Dest funcs @@ -71,17 +72,15 @@ public: static const Cinfo* initCinfo(); private: + double threshold_; double lastTime_; double input_; - bool fired_; - bool useSpikeMode_; + bool fired_; + bool useSpikeMode_; - /** - * @brief Keep the data, each entry is preceeded by time value. - * t0, v0, t1, v1, t2, v2 etc. - */ vector<double> data_; + vector<double> tvec_; /* time data */ vector<string> columns_; /* Store the name of tables */ string tablePath_; diff --git a/builtins/TableBase.cpp b/builtins/TableBase.cpp index e4467c6f..c0976bc2 100644 --- a/builtins/TableBase.cpp +++ b/builtins/TableBase.cpp @@ -14,139 +14,143 @@ const Cinfo* TableBase::initCinfo() { - ////////////////////////////////////////////////////////////// - // Field Definitions - ////////////////////////////////////////////////////////////// - static ValueFinfo< TableBase, vector< double > > vec( - "vector", - "vector with all table entries", - &TableBase::setVec, - &TableBase::getVec - ); - - static ValueFinfo< TableBase, string > plotDump( - "plotDump", - "'File plotname' for dumpling an xplot, as a workaround for an error in the xplot python interface. Note separator is a space. The return value is a dummy.", - &TableBase::setPlotDump, - &TableBase::getPlotDump - ); - - static ReadOnlyValueFinfo< TableBase, double > outputValue( - "outputValue", - "Output value holding current table entry or output of a calculation", - &TableBase::getOutputValue - ); - - static ReadOnlyValueFinfo< TableBase, unsigned int > size( - "size", - "size of table. Note that this is the number of x divisions +1" - "since it must represent the largest value as well as the" - "smallest", - &TableBase::getVecSize - ); - - static ReadOnlyLookupValueFinfo< TableBase, unsigned int, double > y( - "y", - "Value of table at specified index", - &TableBase::getY - ); - - ////////////////////////////////////////////////////////////// - // MsgDest Definitions - ////////////////////////////////////////////////////////////// - - static DestFinfo linearTransform( "linearTransform", - "Linearly scales and offsets data. Scale first, then offset.", - new OpFunc2< TableBase, double, double >( &TableBase::linearTransform ) ); - - static DestFinfo xplot( "xplot", - "Dumps table contents to xplot-format file. " - "Argument 1 is filename, argument 2 is plotname", - new OpFunc2< TableBase, string, string >( &TableBase::xplot ) ); - - static DestFinfo plainPlot( "plainPlot", - "Dumps table contents to single-column ascii file. " - "Uses scientific notation. " - "Argument 1 is filename", - new OpFunc1< TableBase, string >( &TableBase::plainPlot ) ); - - static DestFinfo loadCSV( "loadCSV", - "Reads a single column from a CSV file. " - "Arguments: filename, column#, starting row#, separator", - new OpFunc4< TableBase, string, int, int, char >( - &TableBase::loadCSV ) ); - - static DestFinfo loadXplot( "loadXplot", - "Reads a single plot from an xplot file. " - "Arguments: filename, plotname" - "When the file has 2 columns, the 2nd column is loaded.", - new OpFunc2< TableBase, string, string >( - &TableBase::loadXplot ) ); - - static DestFinfo loadXplotRange( "loadXplotRange", - "Reads a single plot from an xplot file, and selects a " - "subset of points from it. " - "Arguments: filename, plotname, startindex, endindex" - "Uses C convention: startindex included, endindex not included." - "When the file has 2 columns, the 2nd column is loaded.", - new OpFunc4< TableBase, string, string, unsigned int, unsigned int >( - &TableBase::loadXplotRange ) ); - - static DestFinfo compareXplot( "compareXplot", - "Reads a plot from an xplot file and compares with contents of TableBase." - "Result is put in 'output' field of table." - "If the comparison fails (e.g., due to zero entries), the " - "return value is -1." - "Arguments: filename, plotname, comparison_operation" - "Operations: rmsd (for RMSDifference), rmsr (RMSratio ), " - "dotp (Dot product, not yet implemented).", - new OpFunc3< TableBase, string, string, string >( - &TableBase::compareXplot ) ); - - static DestFinfo compareVec( "compareVec", - "Compares contents of TableBase with a vector of doubles." - "Result is put in 'output' field of table." - "If the comparison fails (e.g., due to zero entries), the " - "return value is -1." - "Arguments: Other vector, comparison_operation" - "Operations: rmsd (for RMSDifference), rmsr (RMSratio ), " - "dotp (Dot product, not yet implemented).", - new OpFunc2< TableBase, vector< double >, string >( - &TableBase::compareVec ) ); - - static DestFinfo clearVec( - "clearVec", - "Handles request to clear the data vector", - new OpFunc0< TableBase > (&TableBase::clearVec)); - - - static Finfo* tableBaseFinfos[] = { - &vec, // Value - &plotDump, // Value, used for debugging xplot function. - &outputValue, // ReadOnlyValue - &size, // ReadOnlyValue - &y, // ReadOnlyLookupValue - &linearTransform, // DestFinfo - &xplot, // DestFinfo - &plainPlot, // DestFinfo - &loadCSV, // DestFinfo - &loadXplot, // DestFinfo - &loadXplotRange, // DestFinfo - &compareXplot, // DestFinfo - &compareVec, // DestFinfo - &clearVec, - }; - - static Dinfo< TableBase > dinfo; - static Cinfo tableCinfo ( - "TableBase", - Neutral::initCinfo(), - tableBaseFinfos, - sizeof( tableBaseFinfos ) / sizeof ( Finfo* ), - &dinfo - ); - - return &tableCinfo; + ////////////////////////////////////////////////////////////// + // Field Definitions + ////////////////////////////////////////////////////////////// + static ValueFinfo< TableBase, vector< double > > vec( + "vector", + "vector with all table entries", + &TableBase::setVec, + &TableBase::getVec + ); + + static ValueFinfo< TableBase, string > plotDump( + "plotDump", + "'File plotname' for dumpling an xplot, as a workaround for an error " + " in the xplot python interface. Note separator is a space. The return " + "value is a dummy.", + &TableBase::setPlotDump, + &TableBase::getPlotDump + ); + + static ReadOnlyValueFinfo< TableBase, double > outputValue( + "outputValue", + "Output value holding current table entry or output of a calculation", + &TableBase::getOutputValue + ); + + static ReadOnlyValueFinfo< TableBase, unsigned int > size( + "size", + "size of table. Note that this is the number of x divisions +1" + "since it must represent the largest value as well as the" + "smallest", + &TableBase::getVecSize + ); + + static ReadOnlyLookupValueFinfo< TableBase, unsigned int, double > y( + "y", + "Value of table at specified index", + &TableBase::getY + ); + + ////////////////////////////////////////////////////////////// + // MsgDest Definitions + ////////////////////////////////////////////////////////////// + + static DestFinfo linearTransform( "linearTransform", + "Linearly scales and offsets data. Scale first, then offset.", + new OpFunc2< TableBase + , double + , double >(&TableBase::linearTransform ) ); + + static DestFinfo xplot( "xplot", + "Dumps table contents to xplot-format file. " + "Argument 1 is filename, argument 2 is plotname", + new OpFunc2< TableBase, string, string >( &TableBase::xplot ) ); + + static DestFinfo plainPlot( "plainPlot", + "Dumps table contents to single-column ascii file. " + "Uses scientific notation. " + "Argument 1 is filename", + new OpFunc1< TableBase, string >( &TableBase::plainPlot ) ); + + static DestFinfo loadCSV( "loadCSV", + "Reads a single column from a CSV file. " + "Arguments: filename, column#, starting row#, separator", + new OpFunc4< TableBase, string, int, int, char >(&TableBase::loadCSV ) ); + + static DestFinfo loadXplot( "loadXplot", + "Reads a single plot from an xplot file. " + "Arguments: filename, plotname" + "When the file has 2 columns, the 2nd column is loaded.", + new OpFunc2< TableBase, string, string >( + &TableBase::loadXplot ) ); + + static DestFinfo loadXplotRange( "loadXplotRange", + "Reads a single plot from an xplot file, and selects a " + "subset of points from it. " + "Arguments: filename, plotname, startindex, endindex" + "Uses C convention: startindex included, endindex not included." + "When the file has 2 columns, the 2nd column is loaded.", + new OpFunc4< TableBase, string, string, unsigned int, unsigned int >( + &TableBase::loadXplotRange ) ); + + static DestFinfo compareXplot( "compareXplot", + "Reads a plot from an xplot file and compares with contents of TableBase." + "Result is put in 'output' field of table." + "If the comparison fails (e.g., due to zero entries), the " + "return value is -1." + "Arguments: filename, plotname, comparison_operation" + "Operations: rmsd (for RMSDifference), rmsr (RMSratio ), " + "dotp (Dot product, not yet implemented).", + new OpFunc3< TableBase, string, string, string >( + &TableBase::compareXplot ) ); + + static DestFinfo compareVec( "compareVec", + "Compares contents of TableBase with a vector of doubles." + "Result is put in 'output' field of table." + "If the comparison fails (e.g., due to zero entries), the " + "return value is -1." + "Arguments: Other vector, comparison_operation" + "Operations: rmsd (for RMSDifference), rmsr (RMSratio ), " + "dotp (Dot product, not yet implemented).", + new OpFunc2< TableBase, vector< double >, string >( + &TableBase::compareVec ) ); + + static DestFinfo clearVec( + "clearVec", + "Handles request to clear the data vector", + new OpFunc0< TableBase > (&TableBase::clearVec)); + + + static Finfo* tableBaseFinfos[] = + { + &vec, // Value + &plotDump, // Value, used for debugging xplot function. + &outputValue, // ReadOnlyValue + &size, // ReadOnlyValue + &y, // ReadOnlyLookupValue + &linearTransform, // DestFinfo + &xplot, // DestFinfo + &plainPlot, // DestFinfo + &loadCSV, // DestFinfo + &loadXplot, // DestFinfo + &loadXplotRange, // DestFinfo + &compareXplot, // DestFinfo + &compareVec, // DestFinfo + &clearVec, + }; + + static Dinfo< TableBase > dinfo; + static Cinfo tableCinfo ( + "TableBase", + Neutral::initCinfo(), + tableBaseFinfos, + sizeof( tableBaseFinfos ) / sizeof ( Finfo* ), + &dinfo + ); + + return &tableCinfo; } ////////////////////////////////////////////////////////////// @@ -171,42 +175,44 @@ void TableBase::linearTransform( double scale, double offset ) void TableBase::plainPlot( string fname ) { - ofstream fout( fname.c_str(), ios_base::out ); - fout.precision( 18 ); - fout.setf( ios::scientific, ios::floatfield ); - for ( vector< double >::iterator i = vec_.begin(); i != vec_.end(); ++i) - fout << *i << endl; - fout << "\n"; + ofstream fout( fname.c_str(), ios_base::out ); + fout.precision( 18 ); + fout.setf( ios::scientific, ios::floatfield ); + for ( vector< double >::iterator i = vec_.begin(); i != vec_.end(); ++i) + fout << *i << endl; + fout << "\n"; } void TableBase::xplot( string fname, string plotname ) { - ofstream fout( fname.c_str(), ios_base::app ); - fout << "/newplot\n"; - fout << "/plotname " << plotname << "\n"; - for ( vector< double >::iterator i = vec_.begin(); i != vec_.end(); ++i) - fout << *i << endl; - fout << "\n"; + ofstream fout( fname.c_str(), ios_base::app ); + fout << "/newplot\n"; + fout << "/plotname " << plotname << "\n"; + for ( vector< double >::iterator i = vec_.begin(); i != vec_.end(); ++i) + fout << *i << endl; + fout << "\n"; } bool isNamedPlot( const string& line, const string& plotname ) { - static const unsigned int len = strlen( "/plotname" ) ; - if ( line.size() < len + 2 ) - return 0; - if ( line[0] == '/' && line[1] == 'p' ) { - string name = line.substr( strlen( "/plotname" ) ); - string::size_type pos = name.find_first_not_of( " " ); - if ( pos == string::npos ) { - cout << "TableBase::loadXplot: Malformed plotname line '" << - line << "'\n"; - return 0; - } - name = name.substr( pos ); - if ( plotname == name ) - return 1; - } - return 0; + static const unsigned int len = strlen( "/plotname" ) ; + if ( line.size() < len + 2 ) + return 0; + if ( line[0] == '/' && line[1] == 'p' ) + { + string name = line.substr( strlen( "/plotname" ) ); + string::size_type pos = name.find_first_not_of( " " ); + if ( pos == string::npos ) + { + cout << "TableBase::loadXplot: Malformed plotname line '" << + line << "'\n"; + return 0; + } + name = name.substr( pos ); + if ( plotname == name ) + return 1; + } + return 0; } /* @@ -230,190 +236,212 @@ bool lineHasExactlyTwoNumericalColumns( const string& line ) double getYcolumn( const string& line ) { - istringstream sstream( line ); - double y1 = 0.0; - double y2; - double y3; - - if ( sstream >> y1 ) { - if ( sstream >> y2 ) { - if ( sstream >> y3 ) { - return y1; - } else { - return y2; - } - } - } - return y1; + istringstream sstream( line ); + double y1 = 0.0; + double y2; + double y3; + + if ( sstream >> y1 ) + { + if ( sstream >> y2 ) + { + if ( sstream >> y3 ) + { + return y1; + } + else + { + return y2; + } + } + } + return y1; } bool innerLoadXplot( string fname, string plotname, vector< double >& v ) { - ifstream fin( fname.c_str() ); - if ( !fin.good() ) { - cout << "TableBase::innerLoadXplot: Failed to open file " << fname <<endl; - return 0; - } - - string line; - // Here we advance to the first numerical line. - if ( plotname == "" ) // Just load starting from the 1st numerical line. - { - while ( fin.good() ) { // Break out of this loop if we find a number - getline( fin, line ); - line = moose::trim(line); - if ( isdigit( line[0] ) ) - break;; - if ( line[0] == '-' && line.length() > 1 && isdigit( line[1] ) ) - break; - } - } else { // Find plotname and then begin loading. - while ( fin.good() ) { - getline( fin, line ); - line = moose::trim(line); - if ( isNamedPlot ( line, plotname ) ) { - if ( !getline ( fin, line ) ) - return 0; - break; - } - } - } - - v.resize( 0 ); - do { - if ( line.length() == 0 || line == "/newplot" || line == "/plotname" ) - break; - v.push_back( getYcolumn( line ) ); - getline( fin, line ); - line = moose::trim(line); - } while ( fin.good() ); - - return ( v.size() > 0 ); + ifstream fin( fname.c_str() ); + if ( !fin.good() ) + { + cout << "TableBase::innerLoadXplot: Failed to open file " << fname <<endl; + return 0; + } + + string line; + // Here we advance to the first numerical line. + if ( plotname == "" ) // Just load starting from the 1st numerical line. + { + while ( fin.good() ) // Break out of this loop if we find a number + { + getline( fin, line ); + line = moose::trim(line); + if ( isdigit( line[0] ) ) + break;; + if ( line[0] == '-' && line.length() > 1 && isdigit( line[1] ) ) + break; + } + } + else // Find plotname and then begin loading. + { + while ( fin.good() ) + { + getline( fin, line ); + line = moose::trim(line); + if ( isNamedPlot ( line, plotname ) ) + { + if ( !getline ( fin, line ) ) + return 0; + break; + } + } + } + + v.resize( 0 ); + do + { + if ( line.length() == 0 || line == "/newplot" || line == "/plotname" ) + break; + v.push_back( getYcolumn( line ) ); + getline( fin, line ); + line = moose::trim(line); + } + while ( fin.good() ); + + return ( v.size() > 0 ); } void TableBase::loadXplot( string fname, string plotname ) { - if ( !innerLoadXplot( fname, plotname, vec_ ) ) { - cout << "TableBase::loadXplot: unable to load data from file " << fname <<endl; - return; - } + if ( !innerLoadXplot( fname, plotname, vec_ ) ) + { + cout << "TableBase::loadXplot: unable to load data from file " << fname <<endl; + return; + } } void TableBase::loadXplotRange( string fname, string plotname, - unsigned int start, unsigned int end ) + unsigned int start, unsigned int end ) { - vector< double > temp; - if ( !innerLoadXplot( fname, plotname, temp ) ) { - cout << "TableBase::loadXplot: unable to load data from file " << fname <<endl; - return; - } - if ( start > end || end > temp.size() ) { - cout << "TableBase::loadXplotRange: Bad range (" << start << - ", " << end << "] for table of size " << temp.size() << - " from file " << fname << endl; - return; - } - vec_.clear(); - vec_.insert( vec_.end(), temp.begin() + start, temp.begin() + end ); + vector< double > temp; + if ( !innerLoadXplot( fname, plotname, temp ) ) + { + cout << "TableBase::loadXplot: unable to load data from file " << fname <<endl; + return; + } + if ( start > end || end > temp.size() ) + { + cout << "TableBase::loadXplotRange: Bad range (" << start << + ", " << end << "] for table of size " << temp.size() << + " from file " << fname << endl; + return; + } + vec_.clear(); + vec_.insert( vec_.end(), temp.begin() + start, temp.begin() + end ); } void TableBase::loadCSV( - string fname, int startLine, int colNum, char separator ) + string fname, int startLine, int colNum, char separator ) { cout << "TODO: Not implemented yet" << endl; } double getRMSDiff( const vector< double >& v1, const vector< double >& v2 ) { - unsigned int size = ( v1.size() < v2.size() ) ? v1.size() : v2.size(); - if ( size == 0 ) - return -1; - - double sumsq = 0; - for ( unsigned int i = 0; i < size; ++i ) { - double temp = v1[i] - v2[i]; - sumsq += temp * temp; - } - return sqrt( sumsq / size ); + unsigned int size = ( v1.size() < v2.size() ) ? v1.size() : v2.size(); + if ( size == 0 ) + return -1; + + double sumsq = 0; + for ( unsigned int i = 0; i < size; ++i ) + { + double temp = v1[i] - v2[i]; + sumsq += temp * temp; + } + return sqrt( sumsq / size ); } double getRMS( const vector< double >& v ) { - double sumsq = 0; - unsigned int size = v.size(); - if ( size == 0 ) - return -1; - for ( vector< double >::const_iterator i = v.begin(); i != v.end(); ++i) - sumsq += *i * *i; - - return sqrt( sumsq / size ); + double sumsq = 0; + unsigned int size = v.size(); + if ( size == 0 ) + return -1; + for ( vector< double >::const_iterator i = v.begin(); i != v.end(); ++i) + sumsq += *i * *i; + + return sqrt( sumsq / size ); } double getRMSRatio( const vector< double >& v1, const vector< double >& v2 ) { - double r1 = getRMS( v1 ); - double r2 = getRMS( v2 ); - if ( v1.size() == 0 || v2.size() == 0 ) - return -1; - if ( r1 + r2 > 1e-20 ) - return getRMSDiff( v1, v2 ) / (r1 + r2); - return -1; + double r1 = getRMS( v1 ); + double r2 = getRMS( v2 ); + if ( v1.size() == 0 || v2.size() == 0 ) + return -1; + if ( r1 + r2 > 1e-20 ) + return getRMSDiff( v1, v2 ) / (r1 + r2); + return -1; } string headop( const string& op ) { - const unsigned int len = 5; - char temp[len]; - unsigned int i = 0; - for ( i = 0; i < op.length() && i < len-1 ; ++i ) - temp[i] = tolower( op[i] ); - temp[i] = '\0'; - return string( temp ); + const unsigned int len = 5; + char temp[len]; + unsigned int i = 0; + for ( i = 0; i < op.length() && i < len-1 ; ++i ) + temp[i] = tolower( op[i] ); + temp[i] = '\0'; + return string( temp ); } void TableBase::compareXplot( string fname, string plotname, string op ) { - vector< double > temp; - if ( !innerLoadXplot( fname, plotname, temp ) ) { - cout << "TableBase::compareXplot: unable to load data from file " << fname <<endl; - } - - string hop = headop( op ); - - if ( hop == "rmsd" ) { // RMSDifference - output_ = getRMSDiff( vec_, temp ); - } - - if ( hop == "rmsr" ) { // RMS ratio - output_ = getRMSRatio( vec_, temp ); - } - - if ( hop == "dotp" ) - cout << "TableBase::compareXplot: DotProduct not yet done\n"; + vector< double > temp; + if ( !innerLoadXplot( fname, plotname, temp ) ) + { + cout << "TableBase::compareXplot: unable to load data from file " << fname <<endl; + } + + string hop = headop( op ); + + if ( hop == "rmsd" ) // RMSDifference + { + output_ = getRMSDiff( vec_, temp ); + } + + if ( hop == "rmsr" ) // RMS ratio + { + output_ = getRMSRatio( vec_, temp ); + } + + if ( hop == "dotp" ) + cout << "TableBase::compareXplot: DotProduct not yet done\n"; } void TableBase::compareVec( vector< double > temp, string op ) { - // Note that this line below is illegal: it causes a race condition - // vector< double > temp = Field< vector< double > >::get( other, "vec" ); + // Note that this line below is illegal: it causes a race condition + // vector< double > temp = Field< vector< double > >::get( other, "vec" ); - string hop = headop( op ); + string hop = headop( op ); - if ( hop == "rmsd" ) { // RMSDifference - output_ = getRMSDiff( vec_, temp ); - } + if ( hop == "rmsd" ) // RMSDifference + { + output_ = getRMSDiff( vec_, temp ); + } - if ( hop == "rmsr" ) { // RMS ratio - output_ = getRMSRatio( vec_, temp ); - } + if ( hop == "rmsr" ) // RMS ratio + { + output_ = getRMSRatio( vec_, temp ); + } - if ( hop == "dotp" ) - cout << "TableBase::compareVec: DotProduct not yet done\n"; + if ( hop == "dotp" ) + cout << "TableBase::compareVec: DotProduct not yet done\n"; } void TableBase::clearVec() { - vec_.resize( 0 ); + vec_.resize(0); } ////////////////////////////////////////////////////////////// @@ -422,47 +450,47 @@ void TableBase::clearVec() double TableBase::getOutputValue() const { - return output_; + return output_; } void TableBase::setOutputValue( double v ) { - output_ = v; + output_ = v; } double TableBase::getY( unsigned int index ) const { - if ( index < vec_.size() ) - return ( vec_[index] ); - return 0; + if ( index < vec_.size() ) + return ( vec_[index] ); + return 0; } double TableBase::interpolate( double xmin, double xmax, double input ) - const +const { - if ( vec_.size() == 0 ) - return 0; - if ( vec_.size() == 1 || input < xmin || xmin >= xmax ) - return vec_[0]; - if ( input > xmax ) - return ( vec_.back() ); + if ( vec_.size() == 0 ) + return 0; + if ( vec_.size() == 1 || input < xmin || xmin >= xmax ) + return vec_[0]; + if ( input > xmax ) + return ( vec_.back() ); - unsigned int xdivs = vec_.size() - 1; + unsigned int xdivs = vec_.size() - 1; - double fraction = ( input - xmin ) / ( xmax - xmin ); - if ( fraction < 0 ) - return vec_[0]; + double fraction = ( input - xmin ) / ( xmax - xmin ); + if ( fraction < 0 ) + return vec_[0]; - unsigned int j = xdivs * fraction; - if ( j >= ( vec_.size() - 1 ) ) - return vec_.back(); + unsigned int j = xdivs * fraction; + if ( j >= ( vec_.size() - 1 ) ) + return vec_.back(); - double dx = (xmax - xmin ) / xdivs; - double lowerBound = xmin + j * dx; - double subFraction = ( input - lowerBound ) / dx; + double dx = (xmax - xmin ) / xdivs; + double lowerBound = xmin + j * dx; + double subFraction = ( input - lowerBound ) / dx; - double y = vec_[j] + ( vec_[j + 1] - vec_[j] ) * subFraction; - return y; + double y = vec_[j] + ( vec_[j + 1] - vec_[j] ) * subFraction; + return y; } ////////////////////////////////////////////////////////////// @@ -471,27 +499,27 @@ double TableBase::interpolate( double xmin, double xmax, double input ) void TableBase::setVecSize( unsigned int num ) { - vec_.resize( num ); + vec_.resize( num ); } unsigned int TableBase::getVecSize() const { - return vec_.size(); + return vec_.size(); } vector< double > TableBase::getVec() const { - return vec_; + return vec_; } void TableBase::setVec( vector< double > val ) { - vec_ = val; + vec_ = val; } vector< double >& TableBase::vec() { - return vec_; + return vec_; } // Fetch the const copy of table. Used in Streamer class. @@ -502,18 +530,18 @@ const vector< double >& TableBase::data( ) string TableBase::getPlotDump() const { - static string ret = "plot.Dump"; - return ret; + static string ret = "plot.Dump"; + return ret; } void TableBase::setPlotDump( string v ) { - - std::size_t pos = v.rfind(" "); - string fname = v.substr( 0, pos ); - string plotname = "plot"; - if ( pos != string::npos ) - plotname = v.substr( pos ); - // cout << "setPlotDump( " << fname << ", " << plotname << " ), " << v << "\n"; - xplot( fname, plotname ); + + std::size_t pos = v.rfind(" "); + string fname = v.substr( 0, pos ); + string plotname = "plot"; + if ( pos != string::npos ) + plotname = v.substr( pos ); + // cout << "setPlotDump( " << fname << ", " << plotname << " ), " << v << "\n"; + xplot( fname, plotname ); } diff --git a/builtins/TableBase.h b/builtins/TableBase.h index ada46bec..d0438971 100644 --- a/builtins/TableBase.h +++ b/builtins/TableBase.h @@ -32,8 +32,8 @@ public: double getOutputValue() const; void setOutputValue( double val ); - string getPlotDump() const; - void setPlotDump( string v ); + string getPlotDump() const; + void setPlotDump( string v ); double getY( unsigned int index ) const; diff --git a/hsolve/HSolveActive.cpp b/hsolve/HSolveActive.cpp index 662c4cc8..ecb48c4b 100644 --- a/hsolve/HSolveActive.cpp +++ b/hsolve/HSolveActive.cpp @@ -63,6 +63,7 @@ void HSolveActive::step( ProcPtr info ) sendValues( info ); sendSpikes( info ); + prevExtCurr_ = externalCurrent_; externalCurrent_.assign( externalCurrent_.size(), 0.0 ); } diff --git a/hsolve/HSolveActive.h b/hsolve/HSolveActive.h index affc8525..ad2fd46d 100644 --- a/hsolve/HSolveActive.h +++ b/hsolve/HSolveActive.h @@ -119,6 +119,7 @@ protected: vector< double > externalCurrent_; ///< External currents from ///< channels that HSolve ///< cannot internalize. + vector< double > prevExtCurr_; ///< Last tick's externalCurrent vector< double > externalCalcium_; /// calcium from difshells vector< Id > caConcId_; ///< Used for localIndex-ing. vector< Id > channelId_; ///< Used for localIndex-ing. diff --git a/hsolve/HSolveActiveSetup.cpp b/hsolve/HSolveActiveSetup.cpp index 55edc3be..5ba89611 100644 --- a/hsolve/HSolveActiveSetup.cpp +++ b/hsolve/HSolveActiveSetup.cpp @@ -584,6 +584,7 @@ void HSolveActive::readExternalChannels() //~ externalChannelId_.resize( compartmentId_.size() ); externalCurrent_.resize( 2 * compartmentId_.size(), 0.0 ); + prevExtCurr_.resize( externalCurrent_.size(), 0.0 ); //~ for ( unsigned int ic = 0; ic < compartmentId_.size(); ++ic ) //~ HSolveUtils::targets( diff --git a/hsolve/HSolveInterface.cpp b/hsolve/HSolveInterface.cpp index 548646dd..455c8cb7 100644 --- a/hsolve/HSolveInterface.cpp +++ b/hsolve/HSolveInterface.cpp @@ -170,6 +170,8 @@ double HSolve::getIm( Id id ) const for ( ; icurrent < currentBoundary_[ index ]; ++icurrent ) Im += ( icurrent->Ek - V_[ index ] ) * icurrent->Gk; + assert( 2 * index + 1 < externalCurrent_.size() ); + Im += prevExtCurr_[2*index+1] - prevExtCurr_[2*index]*V_[index]; return Im; } diff --git a/ksolve/testKsolve.cpp b/ksolve/testKsolve.cpp index 64ae8db7..12c0eb88 100644 --- a/ksolve/testKsolve.cpp +++ b/ksolve/testKsolve.cpp @@ -34,309 +34,313 @@ */ Id makeReacTest() { - double simDt = 0.1; - double plotDt = 0.1; - Shell* s = reinterpret_cast< Shell* >( Id().eref().data() ); - - Id pools[10]; - unsigned int i = 0; - // Make the objects. - Id kin = s->doCreate( "CubeMesh", Id(), "kinetics", 1 ); - Id tab = s->doCreate( "StimulusTable", kin, "tab", 1 ); - Id T = pools[i++] = s->doCreate( "BufPool", kin, "T", 1 ); - Id A = pools[i++] = s->doCreate( "Pool", kin, "A", 1 ); - Id B = pools[i++] = s->doCreate( "Pool", kin, "B", 1 ); - Id C = pools[i++] = s->doCreate( "Pool", kin, "C", 1 ); - Id D = pools[i++] = s->doCreate( "Pool", kin, "D", 1 ); - Id E = pools[i++] = s->doCreate( "Pool", kin, "E", 1 ); - Id tot1 = pools[i++] = s->doCreate( "BufPool", kin, "tot1", 1 ); - Id sum = s->doCreate( "Function", tot1, "func", 1 ); // Silly that it has to have this name. - Id sumInput( sum.value() + 1 ); - Id e1Pool = s->doCreate( "Pool", kin, "e1Pool", 1 ); - Id e2Pool = s->doCreate( "Pool", kin, "e2Pool", 1 ); - Id e1 = s->doCreate( "Enz", e1Pool, "e1", 1 ); - Id cplx = s->doCreate( "Pool", e1, "cplx", 1 ); - Id e2 = s->doCreate( "MMenz", e2Pool, "e2", 1 ); - Id r1 = s->doCreate( "Reac", kin, "r1", 1 ); - Id r2 = s->doCreate( "Reac", kin, "r2", 1 ); - Id plots = s->doCreate( "Table2", kin, "plots", 7 ); - - // Connect them up - s->doAddMsg( "Single", tab, "output", T, "setN" ); - - s->doAddMsg( "Single", r1, "sub", T, "reac" ); - s->doAddMsg( "Single", r1, "sub", A, "reac" ); - s->doAddMsg( "Single", r1, "prd", B, "reac" ); - - Field< unsigned int >::set( sum, "numVars", 2 ); - s->doAddMsg( "Single", A, "nOut", ObjId( sumInput, 0, 0 ), "input" ); - s->doAddMsg( "Single", B, "nOut", ObjId( sumInput, 0, 1 ), "input" ); - s->doAddMsg( "Single", sum, "valueOut", tot1, "setN" ); - - s->doAddMsg( "Single", r2, "sub", B, "reac" ); - s->doAddMsg( "Single", r2, "sub", B, "reac" ); - s->doAddMsg( "Single", r2, "prd", C, "reac" ); - - s->doAddMsg( "Single", e1, "sub", C, "reac" ); - s->doAddMsg( "Single", e1, "enz", e1Pool, "reac" ); - s->doAddMsg( "Single", e1, "cplx", cplx, "reac" ); - s->doAddMsg( "Single", e1, "prd", D, "reac" ); - - s->doAddMsg( "Single", e2, "sub", D, "reac" ); - s->doAddMsg( "Single", e2Pool, "nOut", e2, "enzDest" ); - s->doAddMsg( "Single", e2, "prd", E, "reac" ); - - // Set parameters. - Field< double >::set( A, "concInit", 2 ); - Field< double >::set( e1Pool, "concInit", 1 ); - Field< double >::set( e2Pool, "concInit", 1 ); - Field< string >::set( sum, "expr", "x0+x1" ); - Field< double >::set( r1, "Kf", 0.2 ); - Field< double >::set( r1, "Kb", 0.1 ); - Field< double >::set( r2, "Kf", 0.1 ); - Field< double >::set( r2, "Kb", 0.0 ); - Field< double >::set( e1, "Km", 5 ); - Field< double >::set( e1, "kcat", 1 ); - Field< double >::set( e1, "ratio", 4 ); - Field< double >::set( e2, "Km", 5 ); - Field< double >::set( e2, "kcat", 1 ); - vector< double > stim( 100, 0.0 ); - double vol = Field< double >::get( kin, "volume" ); - for ( unsigned int i = 0; i< 100; ++i ) { - stim[i] = vol * NA * (1.0 + sin( i * 2.0 * PI / 100.0 ) ); - } - Field< vector< double > >::set( tab, "vector", stim ); - Field< double >::set( tab, "stepSize", 0.0 ); - Field< double >::set( tab, "stopTime", 10.0 ); - Field< double >::set( tab, "loopTime", 10.0 ); - Field< bool >::set( tab, "doLoop", true ); - - - // Connect outputs - for ( unsigned int i = 0; i < 7; ++i ) - s->doAddMsg( "Single", ObjId( plots,i), - "requestOut", pools[i], "getConc" ); - - // Schedule it. - for ( unsigned int i = 11; i < 18; ++i ) - s->doSetClock( i, simDt ); - s->doSetClock( 18, plotDt ); - /* - s->doUseClock( "/kinetics/##[ISA=Reac],/kinetics/##[ISA=EnzBase],/kinetics/##[ISA=SumFunc]", - "process", 4 ); - s->doUseClock( "/kinetics/##[ISA=PoolBase]", "process", 5 ); - s->doUseClock( "/kinetics/##[ISA=StimulusTable]", - "process", 4 ); - s->doUseClock( "/kinetics/##[ISA=Table]", "process", 8 ); - s->doSetClock( 4, simDt ); - s->doSetClock( 5, simDt ); - s->doSetClock( 8, plotDt ); - */ - return kin; + double simDt = 0.1; + double plotDt = 0.1; + Shell* s = reinterpret_cast< Shell* >( Id().eref().data() ); + + Id pools[10]; + unsigned int i = 0; + // Make the objects. + Id kin = s->doCreate( "CubeMesh", Id(), "kinetics", 1 ); + Id tab = s->doCreate( "StimulusTable", kin, "tab", 1 ); + Id T = pools[i++] = s->doCreate( "BufPool", kin, "T", 1 ); + Id A = pools[i++] = s->doCreate( "Pool", kin, "A", 1 ); + Id B = pools[i++] = s->doCreate( "Pool", kin, "B", 1 ); + Id C = pools[i++] = s->doCreate( "Pool", kin, "C", 1 ); + Id D = pools[i++] = s->doCreate( "Pool", kin, "D", 1 ); + Id E = pools[i++] = s->doCreate( "Pool", kin, "E", 1 ); + Id tot1 = pools[i++] = s->doCreate( "BufPool", kin, "tot1", 1 ); + Id sum = s->doCreate( "Function", tot1, "func", 1 ); // Silly that it has to have this name. + Id sumInput( sum.value() + 1 ); + Id e1Pool = s->doCreate( "Pool", kin, "e1Pool", 1 ); + Id e2Pool = s->doCreate( "Pool", kin, "e2Pool", 1 ); + Id e1 = s->doCreate( "Enz", e1Pool, "e1", 1 ); + Id cplx = s->doCreate( "Pool", e1, "cplx", 1 ); + Id e2 = s->doCreate( "MMenz", e2Pool, "e2", 1 ); + Id r1 = s->doCreate( "Reac", kin, "r1", 1 ); + Id r2 = s->doCreate( "Reac", kin, "r2", 1 ); + Id plots = s->doCreate( "Table2", kin, "plots", 7 ); + + // Connect them up + s->doAddMsg( "Single", tab, "output", T, "setN" ); + + s->doAddMsg( "Single", r1, "sub", T, "reac" ); + s->doAddMsg( "Single", r1, "sub", A, "reac" ); + s->doAddMsg( "Single", r1, "prd", B, "reac" ); + + Field< unsigned int >::set( sum, "numVars", 2 ); + s->doAddMsg( "Single", A, "nOut", ObjId( sumInput, 0, 0 ), "input" ); + s->doAddMsg( "Single", B, "nOut", ObjId( sumInput, 0, 1 ), "input" ); + s->doAddMsg( "Single", sum, "valueOut", tot1, "setN" ); + + s->doAddMsg( "Single", r2, "sub", B, "reac" ); + s->doAddMsg( "Single", r2, "sub", B, "reac" ); + s->doAddMsg( "Single", r2, "prd", C, "reac" ); + + s->doAddMsg( "Single", e1, "sub", C, "reac" ); + s->doAddMsg( "Single", e1, "enz", e1Pool, "reac" ); + s->doAddMsg( "Single", e1, "cplx", cplx, "reac" ); + s->doAddMsg( "Single", e1, "prd", D, "reac" ); + + s->doAddMsg( "Single", e2, "sub", D, "reac" ); + s->doAddMsg( "Single", e2Pool, "nOut", e2, "enzDest" ); + s->doAddMsg( "Single", e2, "prd", E, "reac" ); + + // Set parameters. + Field< double >::set( A, "concInit", 2 ); + Field< double >::set( e1Pool, "concInit", 1 ); + Field< double >::set( e2Pool, "concInit", 1 ); + Field< string >::set( sum, "expr", "x0+x1" ); + Field< double >::set( r1, "Kf", 0.2 ); + Field< double >::set( r1, "Kb", 0.1 ); + Field< double >::set( r2, "Kf", 0.1 ); + Field< double >::set( r2, "Kb", 0.0 ); + Field< double >::set( e1, "Km", 5 ); + Field< double >::set( e1, "kcat", 1 ); + Field< double >::set( e1, "ratio", 4 ); + Field< double >::set( e2, "Km", 5 ); + Field< double >::set( e2, "kcat", 1 ); + vector< double > stim( 100, 0.0 ); + double vol = Field< double >::get( kin, "volume" ); + for ( unsigned int i = 0; i< 100; ++i ) + { + stim[i] = vol * NA * (1.0 + sin( i * 2.0 * PI / 100.0 ) ); + } + Field< vector< double > >::set( tab, "vector", stim ); + Field< double >::set( tab, "stepSize", 0.0 ); + Field< double >::set( tab, "stopTime", 10.0 ); + Field< double >::set( tab, "loopTime", 10.0 ); + Field< bool >::set( tab, "doLoop", true ); + + + // Connect outputs + for ( unsigned int i = 0; i < 7; ++i ) + s->doAddMsg( "Single", ObjId( plots,i), + "requestOut", pools[i], "getConc" ); + + // Schedule it. + for ( unsigned int i = 11; i < 18; ++i ) + s->doSetClock( i, simDt ); + s->doSetClock( 18, plotDt ); + /* + s->doUseClock( "/kinetics/##[ISA=Reac],/kinetics/##[ISA=EnzBase],/kinetics/##[ISA=SumFunc]", + "process", 4 ); + s->doUseClock( "/kinetics/##[ISA=PoolBase]", "process", 5 ); + s->doUseClock( "/kinetics/##[ISA=StimulusTable]", + "process", 4 ); + s->doUseClock( "/kinetics/##[ISA=Table]", "process", 8 ); + s->doSetClock( 4, simDt ); + s->doSetClock( 5, simDt ); + s->doSetClock( 8, plotDt ); + */ + return kin; } void testSetupReac() { - Shell* s = reinterpret_cast< Shell* >( Id().eref().data() ); - Id kin = makeReacTest(); - s->doReinit(); - s->doStart( 20.0 ); - Id plots( "/kinetics/plots" ); - /* - for ( unsigned int i = 0; i < 7; ++i ) { - stringstream ss; - ss << "plot." << i; - SetGet2< string, string >::set( ObjId( plots, i ), "xplot", - "tsr.plot", ss.str() ); - } - */ - s->doDelete( kin ); - cout << "." << flush; + Shell* s = reinterpret_cast< Shell* >( Id().eref().data() ); + Id kin = makeReacTest(); + s->doReinit(); + s->doStart( 20.0 ); + Id plots( "/kinetics/plots" ); + /* + for ( unsigned int i = 0; i < 7; ++i ) { + stringstream ss; + ss << "plot." << i; + SetGet2< string, string >::set( ObjId( plots, i ), "xplot", + "tsr.plot", ss.str() ); + } + */ + s->doDelete( kin ); + cout << "." << flush; } void testBuildStoich() { - // In the updated version, we have reordered all pools and reacs by - // Id number, modulo varPools then bufPOols. - // Matrix looks like: - // Reac Name R1 R2 e1a e1b e2 - // MolName - // D -1 0 0 0 0 - // A -1 0 0 0 0 - // B +1 -2 0 0 0 - // C 0 +1 -1 0 0 - // enz1 0 0 -1 +1 0 - // e1cplx 0 0 +1 -1 0 - // E 0 0 0 +1 -1 - // F 0 0 0 0 +1 - // enz2 0 0 0 0 0 - // tot1 0 0 0 0 0 - // - // This has been shuffled to: - // A -1 0 0 0 0 - // B +1 -2 0 0 0 - // C 0 +1 -1 0 0 - // E 0 0 0 +1 -1 - // F 0 0 0 0 +1 - // enz1 0 0 -1 +1 0 - // enz2 0 0 0 0 0 - // e1cplx 0 0 +1 -1 0 - // D -1 0 0 0 0 - // tot1 0 0 0 0 0 - // - // (This is the output of the print command on the sparse matrix.) - // - Shell* s = reinterpret_cast< Shell* >( Id().eref().data() ); - Id kin = makeReacTest(); - Id ksolve = s->doCreate( "Ksolve", kin, "ksolve", 1 ); - Id stoich = s->doCreate( "Stoich", ksolve, "stoich", 1 ); - Field< Id >::set( stoich, "compartment", kin ); - Field< Id >::set( stoich, "ksolve", ksolve ); - - // Used to get at the stoich matrix from gdb. + // In the updated version, we have reordered all pools and reacs by + // Id number, modulo varPools then bufPOols. + // Matrix looks like: + // Reac Name R1 R2 e1a e1b e2 + // MolName + // D -1 0 0 0 0 + // A -1 0 0 0 0 + // B +1 -2 0 0 0 + // C 0 +1 -1 0 0 + // enz1 0 0 -1 +1 0 + // e1cplx 0 0 +1 -1 0 + // E 0 0 0 +1 -1 + // F 0 0 0 0 +1 + // enz2 0 0 0 0 0 + // tot1 0 0 0 0 0 + // + // This has been shuffled to: + // A -1 0 0 0 0 + // B +1 -2 0 0 0 + // C 0 +1 -1 0 0 + // E 0 0 0 +1 -1 + // F 0 0 0 0 +1 + // enz1 0 0 -1 +1 0 + // enz2 0 0 0 0 0 + // e1cplx 0 0 +1 -1 0 + // D -1 0 0 0 0 + // tot1 0 0 0 0 0 + // + // (This is the output of the print command on the sparse matrix.) + // + Shell* s = reinterpret_cast< Shell* >( Id().eref().data() ); + Id kin = makeReacTest(); + Id ksolve = s->doCreate( "Ksolve", kin, "ksolve", 1 ); + Id stoich = s->doCreate( "Stoich", ksolve, "stoich", 1 ); + Field< Id >::set( stoich, "compartment", kin ); + Field< Id >::set( stoich, "ksolve", ksolve ); + + // Used to get at the stoich matrix from gdb. #ifndef NDEBUG - Stoich* stoichPtr = reinterpret_cast< Stoich* >( stoich.eref().data() ); + Stoich* stoichPtr = reinterpret_cast< Stoich* >( stoich.eref().data() ); #endif - Field< string >::set( stoich, "path", "/kinetics/##" ); - - unsigned int n = Field< unsigned int >::get( stoich, "numAllPools" ); - assert( n == 10 ); - unsigned int r = Field< unsigned int >::get( stoich, "numRates" ); - assert( r == 5 ); // One each for reacs and MMenz, two for Enz. - - vector< int > entries = Field< vector< int > >::get( stoich, - "matrixEntry" ); - vector< unsigned int > colIndex = Field< vector< unsigned int > >::get( - stoich, "columnIndex" ); - vector< unsigned int > rowStart = Field< vector< unsigned int > >::get( - stoich, "rowStart" ); - - assert( rowStart.size() == n + 1 ); - assert( entries.size() == colIndex.size() ); - assert( entries.size() == 13 ); - assert( entries[0] == -1 ); - assert( entries[1] == 1 ); - assert( entries[2] == -2 ); - assert( entries[3] == 1 ); - assert( entries[4] == -1 ); - assert( entries[5] == 1 ); - assert( entries[6] == -1 ); - assert( entries[7] == 1 ); - assert( entries[8] == -1 ); - assert( entries[9] == 1 ); - assert( entries[10] == 1 ); - assert( entries[11] == -1 ); - assert( entries[12] == -1 ); - - s->doDelete( kin ); - cout << "." << flush; + Field< string >::set( stoich, "path", "/kinetics/##" ); + + unsigned int n = Field< unsigned int >::get( stoich, "numAllPools" ); + assert( n == 10 ); + unsigned int r = Field< unsigned int >::get( stoich, "numRates" ); + assert( r == 5 ); // One each for reacs and MMenz, two for Enz. + + vector< int > entries = Field< vector< int > >::get( stoich, + "matrixEntry" ); + vector< unsigned int > colIndex = Field< vector< unsigned int > >::get( + stoich, "columnIndex" ); + vector< unsigned int > rowStart = Field< vector< unsigned int > >::get( + stoich, "rowStart" ); + + assert( rowStart.size() == n + 1 ); + assert( entries.size() == colIndex.size() ); + assert( entries.size() == 13 ); + assert( entries[0] == -1 ); + assert( entries[1] == 1 ); + assert( entries[2] == -2 ); + assert( entries[3] == 1 ); + assert( entries[4] == -1 ); + assert( entries[5] == 1 ); + assert( entries[6] == -1 ); + assert( entries[7] == 1 ); + assert( entries[8] == -1 ); + assert( entries[9] == 1 ); + assert( entries[10] == 1 ); + assert( entries[11] == -1 ); + assert( entries[12] == -1 ); + + s->doDelete( kin ); + cout << "." << flush; } void testRunKsolve() { - double simDt = 0.1; - // double plotDt = 0.1; - Shell* s = reinterpret_cast< Shell* >( Id().eref().data() ); - Id kin = makeReacTest(); - Id ksolve = s->doCreate( "Ksolve", kin, "ksolve", 1 ); - Id stoich = s->doCreate( "Stoich", ksolve, "stoich", 1 ); - Field< Id >::set( stoich, "compartment", kin ); - Field< Id >::set( stoich, "ksolve", ksolve ); - Field< string >::set( stoich, "path", "/kinetics/##" ); - s->doUseClock( "/kinetics/ksolve", "process", 4 ); - s->doSetClock( 4, simDt ); - - s->doReinit(); - s->doStart( 20.0 ); - Id plots( "/kinetics/plots" ); - for ( unsigned int i = 0; i < 7; ++i ) { - stringstream ss; - ss << "plot." << i; - SetGet2< string, string >::set( ObjId( plots, i ), "xplot", - "tsr2.plot", ss.str() ); - } - s->doDelete( kin ); - cout << "." << flush; + double simDt = 0.1; + // double plotDt = 0.1; + Shell* s = reinterpret_cast< Shell* >( Id().eref().data() ); + Id kin = makeReacTest(); + Id ksolve = s->doCreate( "Ksolve", kin, "ksolve", 1 ); + Id stoich = s->doCreate( "Stoich", ksolve, "stoich", 1 ); + Field< Id >::set( stoich, "compartment", kin ); + Field< Id >::set( stoich, "ksolve", ksolve ); + Field< string >::set( stoich, "path", "/kinetics/##" ); + s->doUseClock( "/kinetics/ksolve", "process", 4 ); + s->doSetClock( 4, simDt ); + + s->doReinit(); + s->doStart( 20.0 ); + Id plots( "/kinetics/plots" ); + for ( unsigned int i = 0; i < 7; ++i ) + { + stringstream ss; + ss << "plot." << i; + SetGet2< string, string >::set( ObjId( plots, i ), "xplot", + "tsr2.plot", ss.str() ); + } + s->doDelete( kin ); + cout << "." << flush; } void testRunGsolve() { - double simDt = 0.1; - // double plotDt = 0.1; - Shell* s = reinterpret_cast< Shell* >( Id().eref().data() ); - Id kin = makeReacTest(); - double volume = 1e-21; - Field< double >::set( kin, "volume", volume ); - Field< double >::set( ObjId( "/kinetics/A" ), "concInit", 2 ); - Field< double >::set( ObjId( "/kinetics/e1Pool" ), "concInit", 1 ); - Field< double >::set( ObjId( "/kinetics/e2Pool" ), "concInit", 1 ); - Id e1( "/kinetics/e1Pool/e1" ); - Field< double >::set( e1, "Km", 5 ); - Field< double >::set( e1, "kcat", 1 ); - vector< double > stim( 100, 0.0 ); - for ( unsigned int i = 0; i< 100; ++i ) { - stim[i] = volume * NA * (1.0 + sin( i * 2.0 * PI / 100.0 ) ); - } - Field< vector< double > >::set( ObjId( "/kinetics/tab" ), "vector", stim ); - - - Id gsolve = s->doCreate( "Gsolve", kin, "gsolve", 1 ); - Id stoich = s->doCreate( "Stoich", gsolve, "stoich", 1 ); - Field< Id >::set( stoich, "compartment", kin ); - Field< Id >::set( stoich, "ksolve", gsolve ); - - Field< string >::set( stoich, "path", "/kinetics/##" ); - s->doUseClock( "/kinetics/gsolve", "process", 4 ); - s->doSetClock( 4, simDt ); - - s->doReinit(); - s->doStart( 20.0 ); - Id plots( "/kinetics/plots" ); - for ( unsigned int i = 0; i < 7; ++i ) { - stringstream ss; - ss << "plot." << i; - SetGet2< string, string >::set( ObjId( plots, i ), "xplot", - "tsr3.plot", ss.str() ); - } - s->doDelete( kin ); - cout << "." << flush; + double simDt = 0.1; + // double plotDt = 0.1; + Shell* s = reinterpret_cast< Shell* >( Id().eref().data() ); + Id kin = makeReacTest(); + double volume = 1e-21; + Field< double >::set( kin, "volume", volume ); + Field< double >::set( ObjId( "/kinetics/A" ), "concInit", 2 ); + Field< double >::set( ObjId( "/kinetics/e1Pool" ), "concInit", 1 ); + Field< double >::set( ObjId( "/kinetics/e2Pool" ), "concInit", 1 ); + Id e1( "/kinetics/e1Pool/e1" ); + Field< double >::set( e1, "Km", 5 ); + Field< double >::set( e1, "kcat", 1 ); + vector< double > stim( 100, 0.0 ); + for ( unsigned int i = 0; i< 100; ++i ) + { + stim[i] = volume * NA * (1.0 + sin( i * 2.0 * PI / 100.0 ) ); + } + Field< vector< double > >::set( ObjId( "/kinetics/tab" ), "vector", stim ); + + + Id gsolve = s->doCreate( "Gsolve", kin, "gsolve", 1 ); + Id stoich = s->doCreate( "Stoich", gsolve, "stoich", 1 ); + Field< Id >::set( stoich, "compartment", kin ); + Field< Id >::set( stoich, "ksolve", gsolve ); + + Field< string >::set( stoich, "path", "/kinetics/##" ); + s->doUseClock( "/kinetics/gsolve", "process", 4 ); + s->doSetClock( 4, simDt ); + + s->doReinit(); + s->doStart( 20.0 ); + Id plots( "/kinetics/plots" ); + for ( unsigned int i = 0; i < 7; ++i ) + { + stringstream ss; + ss << "plot." << i; + SetGet2< string, string >::set( ObjId( plots, i ), "xplot", + "tsr3.plot", ss.str() ); + } + s->doDelete( kin ); + cout << "." << flush; } void testFuncTerm() { - FuncTerm ft; - ft.setExpr( "x0 + x1 * t" ); - double args[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; - - // First check that it doesn't die even if we forget to set up anything. - double ans = ft( args, 2.0 ); - - vector< unsigned int > mol( 2, 0 ); - mol[0] = 2; - mol[1] = 0; - ft.setReactantIndex( mol ); - - ans = ft( args, 10.0 ); - assert( doubleEq( ans, 13.0 ) ); - mol[0] = 0; - mol[1] = 9; - ft.setReactantIndex( mol ); - ans = ft( args, 2.0 ); - assert( doubleEq( ans, 21.0 ) ); - cout << "." << flush; + FuncTerm ft; + ft.setExpr( "x0 + x1 * t" ); + double args[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + // First check that it doesn't die even if we forget to set up anything. + double ans = ft( args, 2.0 ); + + vector< unsigned int > mol( 2, 0 ); + mol[0] = 2; + mol[1] = 0; + ft.setReactantIndex( mol ); + + ans = ft( args, 10.0 ); + assert( doubleEq( ans, 13.0 ) ); + mol[0] = 0; + mol[1] = 9; + ft.setReactantIndex( mol ); + ans = ft( args, 2.0 ); + assert( doubleEq( ans, 21.0 ) ); + cout << "." << flush; } void testKsolve() { - testSetupReac(); - testBuildStoich(); - testRunKsolve(); - testRunGsolve(); - testFuncTerm(); + testSetupReac(); + testBuildStoich(); + testRunKsolve(); + testRunGsolve(); + testFuncTerm(); } void testKsolveProcess() { -; + ; } diff --git a/pymoose/moosemodule.cpp b/pymoose/moosemodule.cpp index 5e811d02..0a71f466 100644 --- a/pymoose/moosemodule.cpp +++ b/pymoose/moosemodule.cpp @@ -17,9 +17,10 @@ #include <map> #include <ctime> #include <csignal> +#include <chrono> +#include <thread> #include <exception> - #if USE_BOOST_ODE #include <boost/format.hpp> #endif @@ -88,6 +89,8 @@ extern void speedTestMultiNodeIntFireNetwork( extern void mooseBenchmarks( unsigned int option ); +// global variable. +bool tcpSocketStreamerEnabled_ = false; /*----------------------------------------------------------------------------- * Random number generator for this module. @@ -107,6 +110,31 @@ double pymoose_mtrand_( void ) return moose::mtrand( ); } +bool setupSocketStreamer(const string addr ) +{ + LOG(moose::debug, "Setting streamer with addr " << addr ); + + // Find all tables. + vector< ObjId > tables; + wildcardFind( "/##[TYPE=Table2]", tables ); + wildcardFind( "/##[TYPE=Table]", tables, false ); + + if( tables.size() < 1 ) + { + LOG( moose::warning, "No table found. MOOSE will not create a streamer." ); + return false; + } + + // Craete a SocketStreamer and add all tables. + Id stBase = SHELLPTR->doCreate("Neutral", Id(), "socket", 1); + Id st = SHELLPTR->doCreate("SocketStreamer", stBase, "streamer", 1); + Field<string>::set(st, "address", addr); + + for( auto &t : tables ) + SetGet1<Id>::set(st, "addTable", t.id ); + return true; +} + /** Utility function to get all the individual elements when ALLDATA is dataIndex. */ @@ -1721,10 +1749,8 @@ PyObject * moose_start(PyObject * dummy, PyObject * args ) sigemptyset(&sigHandler.sa_mask); sigHandler.sa_flags = 0; sigaction(SIGINT, &sigHandler, NULL); - SHELLPTR->doStart( runtime, notify ); Py_RETURN_NONE; - } PyDoc_STRVAR(moose_reinit_documentation, @@ -1742,9 +1768,20 @@ PyDoc_STRVAR(moose_reinit_documentation, "\n"); PyObject * moose_reinit(PyObject * dummy, PyObject * args) { + // If environment variable MOOSE_TCP_STREAMER_ADDRESS is set then setup the + // streamer. + string envSocketServer = moose::getEnv( "MOOSE_STREAMER_ADDRESS" ); + if(! envSocketServer.empty()) + { + LOG( moose::debug, "Environment variable set of socket" << envSocketServer ); + if( envSocketServer.size() > 0 ) + setupSocketStreamer(envSocketServer); + } + SHELLPTR->doReinit(); Py_RETURN_NONE; } + PyObject * moose_stop(PyObject * dummy, PyObject * args) { SHELLPTR->doStop(); @@ -1765,10 +1802,12 @@ PyObject * moose_exists(PyObject * dummy, PyObject * args) return Py_BuildValue("i", Id(path) != Id() || string(path) == "/" || string(path) == "/root"); } -PyDoc_STRVAR(moose_loadModel_documentation, - "loadModel(filename, modelpath, solverclass) -> vec\n" +PyDoc_STRVAR(moose_loadModelInternal_documentation, + "loadModelInternal(filename, modelpath, solverclass) -> vec\n" "\n" "Load model from a file to a specified path.\n" + "Note: This function should not be used by users. It is meants for developers. \n" + "Please see `moose.loadModel` function.\n" "\n" "Parameters\n" "----------\n" @@ -1785,11 +1824,11 @@ PyDoc_STRVAR(moose_loadModel_documentation, " loaded model container vec.\n" ); -PyObject * moose_loadModel(PyObject * dummy, PyObject * args) +PyObject * moose_loadModelInternal(PyObject * dummy, PyObject * args) { char * fname = NULL, * modelpath = NULL, * solverclass = NULL; - if(!PyArg_ParseTuple(args, "ss|s:moose_loadModel", &fname, &modelpath, &solverclass)) + if(!PyArg_ParseTuple(args, "ss|s:moose_loadModelInternal", &fname, &modelpath, &solverclass)) { cout << "here in moose load"; return NULL; @@ -1812,7 +1851,8 @@ PyObject * moose_loadModel(PyObject * dummy, PyObject * args) PyObject * ret = reinterpret_cast<PyObject*>(model); return ret; } -/* + +#if 0 PyDoc_STRVAR(moose_saveModel_documentation, "saveModel(source, filename) -> None\n" "\n" @@ -1869,7 +1909,8 @@ PyObject * moose_saveModel(PyObject * dummy, PyObject * args) SHELLPTR->doSaveModel(model, filename); Py_RETURN_NONE; } -*/ +#endif + PyObject * moose_setCwe(PyObject * dummy, PyObject * args) { PyObject * element = NULL; @@ -3013,7 +3054,7 @@ static PyMethodDef MooseMethods[] = {"stop", (PyCFunction)moose_stop, METH_VARARGS, "Stop simulation"}, {"isRunning", (PyCFunction)moose_isRunning, METH_VARARGS, "True if the simulation is currently running."}, {"exists", (PyCFunction)moose_exists, METH_VARARGS, "True if there is an object with specified path."}, - {"loadModel", (PyCFunction)moose_loadModel, METH_VARARGS, moose_loadModel_documentation}, + {"loadModelInternal", (PyCFunction)moose_loadModelInternal, METH_VARARGS, moose_loadModelInternal_documentation}, //{"saveModel", (PyCFunction)moose_saveModel, METH_VARARGS, moose_saveModel_documentation}, {"connect", (PyCFunction)moose_connect, METH_VARARGS, moose_connect_documentation}, {"getCwe", (PyCFunction)moose_getCwe, METH_VARARGS, "Get the current working element. 'pwe' is an alias of this function."}, @@ -3232,33 +3273,3 @@ PyMODINIT_FUNC MODINIT(_moose) return moose_module; #endif } - - -////////////////////////////////////////////// -// Main function -////////////////////////////////////////////// - -// int main(int argc, char* argv[]) -// { -// #ifdef PY3K -// size_t len = strlen(argv[0]); -// wchar_t * warg = (wchar_t*)calloc(sizeof(wchar_t), len); -// mbstowcs(warg, argv[0], len); -// #else -// char * warg = argv[0]; -// #endif -// for (int ii = 0; ii < argc; ++ii){ -// cout << "ARGV: " << argv[ii]; -// } -// cout << endl; -// Py_SetProgramName(warg); -// Py_Initialize(); -// MODINIT(_moose); -// #ifdef PY3K -// free(warg); -// #endif -// return 0; -// } - -// -// moosemodule.cpp ends here diff --git a/pymoose/moosemodule.h b/pymoose/moosemodule.h index 7ef0e793..470b17f1 100644 --- a/pymoose/moosemodule.h +++ b/pymoose/moosemodule.h @@ -234,7 +234,7 @@ PyObject * moose_reinit(PyObject * dummy, PyObject * args); PyObject * moose_stop(PyObject * dummy, PyObject * args); PyObject * moose_isRunning(PyObject * dummy, PyObject * args); PyObject * moose_exists(PyObject * dummy, PyObject * args); -PyObject * moose_loadModel(PyObject * dummy, PyObject * args); +PyObject * moose_loadModelInternal(PyObject * dummy, PyObject * args); //PyObject * moose_saveModel(PyObject * dummy, PyObject * args); PyObject * moose_setCwe(PyObject * dummy, PyObject * args); PyObject * moose_getCwe(PyObject * dummy, PyObject * args); diff --git a/python/moose/SBML/readSBML.py b/python/moose/SBML/readSBML.py index f8e74f7e..356d2400 100644 --- a/python/moose/SBML/readSBML.py +++ b/python/moose/SBML/readSBML.py @@ -13,10 +13,14 @@ ** copyright (C) 2003-2017 Upinder S. Bhalla. and NCBS Created : Thu May 13 10:19:00 2016(+0530) Version -Last-Updated: Fri Oct 26 11:21:00 2018(+0530) +Last-Updated: Tue Dec 3 17:30:00 2018(+0530) By:HarshaRani **********************************************************************/ 2018 +Dec 3: - reading motor and diffconstant from pool +Nov 30: - groups and subgroups are read from xml to moose +Nov 19: - reading and creating CylMesh and EndoMesh if specified in the Annotation field in compartment + definition, also checking if EndoMesh missing/wrong surround compartment Oct 26: - validator can be switchedoff by passing validate="off" while readSBML files May 18: - cleanedup and connected cplx pool to correct parent enzyme Jan 6: - only if valid model exists, then printing the no of compartment,pool,reaction etc @@ -78,7 +82,7 @@ try: except ImportError: pass -def mooseReadSBML(filepath, loadpath, solver="ee",validate="on"): +def mooseReadSBML(filepath, loadpath, solver="ee",validate="True"): """Load SBML model """ global foundLibSBML_ @@ -101,7 +105,7 @@ def mooseReadSBML(filepath, loadpath, solver="ee",validate="on"): filep = open(filepath, "r") document = libsbml.readSBML(filepath) tobecontinue = False - if validate == "on": + if validate == "True": tobecontinue = validateModel(document) else: tobecontinue = True @@ -142,7 +146,8 @@ def mooseReadSBML(filepath, loadpath, solver="ee",validate="on"): globparameterIdValue = {} mapParameter(model, globparameterIdValue) - errorFlag = createCompartment( + msgCmpt = "" + errorFlag,msgCmpt = createCompartment( basePath, model, comptSbmlidMooseIdMap) groupInfo = checkGroup(basePath,model) @@ -159,7 +164,7 @@ def mooseReadSBML(filepath, loadpath, solver="ee",validate="on"): model, specInfoMap, modelAnnotaInfo, globparameterIdValue,funcDef,groupInfo) if len(moose.wildcardFind(moose.element(loadpath).path+"/##[ISA=ReacBase],/##[ISA=EnzBase]")) == 0: errorFlag = False - noRE = ("Atleast one reaction should be present ") + noRE = ("Atleast one reaction should be present to display in the widget ") getModelAnnotation( model, baseId, basePath) if not errorFlag: @@ -197,9 +202,9 @@ def mooseReadSBML(filepath, loadpath, solver="ee",validate="on"): moose.delete(basePath) loadpath = moose.Shell('/') #return basePath, "" - loaderror = msgRule+msgReac+noRE + loaderror = msgCmpt+str(msgRule)+msgReac+noRE if loaderror != "": - loaderror = loaderror +" to display in the widget" + loaderror = loaderror return moose.element(loadpath), loaderror else: print("Validation failed while reading the model.") @@ -223,6 +228,7 @@ def checkFuncDef(model): if foundbvar and foundfuncMathML: funcDef[f.getName()] = {'bvar':bvar, "MathML": fmath.getRightChild()} return funcDef + def checkGroup(basePath,model): groupInfo = {} modelAnnotaInfo = {} @@ -235,26 +241,36 @@ def checkGroup(basePath,model): groupAnnoInfo = getObjAnnotation(p, modelAnnotaInfo) if groupAnnoInfo != {}: 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()) + if "Group" in groupAnnoInfo: + if moose.exists(basePath.path+'/'+groupAnnoInfo["Compartment"]+'/'+groupAnnoInfo["Group"]): + if moose.exists(basePath.path+'/'+groupAnnoInfo["Compartment"]+'/'+groupAnnoInfo["Group"]+'/'+p.getName()): + moosegrp = moose.element(basePath.path+'/'+groupAnnoInfo["Compartment"]+'/'+groupAnnoInfo["Group"]+'/'+p.getName()) + else: + moosegrp = moose.Neutral(basePath.path+'/'+groupAnnoInfo["Compartment"]+'/'+groupAnnoInfo["Group"]+'/'+p.getName()) + else: + moose.Neutral(basePath.path+'/'+groupAnnoInfo["Compartment"]+'/'+groupAnnoInfo["Group"]) + if moose.exists(basePath.path+'/'+groupAnnoInfo["Compartment"]+'/'+groupAnnoInfo["Group"]+'/'+p.getName()): + moosegrp = moose.element(basePath.path+'/'+groupAnnoInfo["Compartment"]+'/'+groupAnnoInfo["Group"]+'/'+p.getName()) + else: + moosegrp = moose.Neutral(basePath.path+'/'+groupAnnoInfo["Compartment"]+'/'+groupAnnoInfo["Group"]+'/'+p.getName()) else: - moosegrp = moose.element(basePath.path+'/'+groupAnnoInfo["Compartment"]+'/'+p.getId()) + if not moose.exists(basePath.path+'/'+groupAnnoInfo["Compartment"]+'/'+p.getName()): + moosegrp = moose.Neutral(basePath.path+'/'+groupAnnoInfo["Compartment"]+'/'+p.getName()) + else: + moosegrp = moose.element(basePath.path+'/'+groupAnnoInfo["Compartment"]+'/'+p.getName()) moosegrpinfo = moose.Annotator(moosegrp.path+'/info') moosegrpinfo.color = groupAnnoInfo["bgColor"] - else: - print ("Compartment not found") - + else: + print ("Compartment not found") if p.getKind() == 2: if p.getId() not in groupInfo: - #groupInfo[p.getId()] + memlists = [] 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()] + memlists.append(mem.getIdRef()) + groupInfo[p.getId()] = {"mpath":moosegrp, "splist":memlists} return groupInfo + def setupEnzymaticReaction(enz, groupName, enzName, specInfoMap, modelAnnotaInfo,deletcplxMol): enzPool = (modelAnnotaInfo[groupName]["enzyme"]) @@ -402,6 +418,36 @@ def getModelAnnotation(obj, baseId, basepath): tablelistname.append(fullPath) moose.connect(tab, "requestOut", plotSId, "getConc") +def getCmptAnnotation(obj): + 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() in["CompartmentAnnotation"])): + sublist = [] + for gch in range(0, childNode.getNumChildren()): + grandChildNode = childNode.getChild(gch) + nodeName = grandChildNode.getName() + nodeValue = "" + if (grandChildNode.getNumChildren() == 1): + nodeValue = grandChildNode.getChild(0).toXMLString() + else: + print( + "Error: expected exactly ONE child of ", nodeName) + if nodeName == "Mesh": + annotateMap[nodeName] = nodeValue + if nodeName == "numDiffCompts": + annotateMap[nodeName] = nodeValue + if nodeName == "isMembraneBound": + annotateMap[nodeName] = nodeValue + if nodeName == "totLength": + annotateMap[nodeName] = nodeValue + if nodeName == "diffLength": + annotateMap[nodeName] = nodeValue + if nodeName == "surround": + annotateMap[nodeName] = nodeValue + return annotateMap def getObjAnnotation(obj, modelAnnotationInfo): name = obj.getId() @@ -436,6 +482,10 @@ def getObjAnnotation(obj, modelAnnotationInfo): annotateMap[nodeName] = nodeValue if nodeName == "Compartment": annotateMap[nodeName] = nodeValue + if nodeName == "diffConstant": + annotateMap[nodeName] = nodeValue + if nodeName == "motorConstant": + annotateMap[nodeName] = nodeValue return annotateMap @@ -572,9 +622,13 @@ def createReaction(model, specInfoMap, modelAnnotaInfo, globparameterIdValue,fun if (reac.isSetId()): rId = reac.getId() - groups = [k for k, v in groupInfo.items() if rId in v] - if groups: - group = groups[0] + #groups = [k for k, v in groupInfo.items() if rId in v] + for k,v in groupInfo.items(): + if rId in v["splist"]: + group = v["mpath"] + + # if groups: + # group = groups[0] if (reac.isSetName()): rName = reac.getName() rName = rName.replace(" ", "_space_") @@ -648,12 +702,12 @@ def createReaction(model, specInfoMap, modelAnnotaInfo, globparameterIdValue,fun sp = react.getSpecies() sp = str(idBeginWith(sp)) speCompt = specInfoMap[sp]["comptId"].path - if group: - if moose.exists(speCompt+'/'+group): - speCompt = speCompt+'/'+group - else: - speCompt = (moose.Neutral(speCompt+'/'+group)).path + speCompt = group.path + # if moose.exists(speCompt+'/'+group): + # speCompt = speCompt+'/'+group + # else: + # speCompt = (moose.Neutral(speCompt+'/'+group)).path if moose.exists(speCompt + '/' + rName): rName =rId reaction_ = moose.Reac(speCompt + '/' + rName) @@ -1092,7 +1146,6 @@ def pullnotes(sbmlId, mooseId): objInfo = moose.element(mooseId.path + '/info') objInfo.notes = notes - def createSpecies(basePath, model, comptSbmlidMooseIdMap, specInfoMap, modelAnnotaInfo,groupInfo): # ToDo: @@ -1112,10 +1165,13 @@ def createSpecies(basePath, model, comptSbmlidMooseIdMap, sName = None sId = spe.getId() - - groups = [k for k, v in groupInfo.items() if sId in v] - if groups: - group = groups[0] + group = "" + #groups = [k for k, v in groupInfo.items() if sId in v] + for k,v in groupInfo.items(): + if sId in v["splist"]: + group = v["mpath"] + # if groups: + # group = groups[0] if spe.isSetName(): sName = spe.getName() sName = sName.replace(" ", "_space_") @@ -1133,10 +1189,11 @@ def createSpecies(basePath, model, comptSbmlidMooseIdMap, # "false": is {unit of amount}/{unit of size} (i.e., concentration or density). # "true": then the value is interpreted as having a unit of amount only. if group: - if moose.exists(comptEl+'/'+group): - comptEl = comptEl+'/'+group - else: - comptEl = (moose.Neutral(comptEl+'/'+group)).path + comptEl = group.path + # if moose.exists(comptEl+'/'+group): + # comptEl = comptEl+'/'+group + # else: + # comptEl = (moose.Neutral(comptEl+'/'+group)).path if (boundaryCondition): poolId = moose.BufPool(comptEl + '/' + sName) else: @@ -1159,7 +1216,10 @@ def createSpecies(basePath, model, comptSbmlidMooseIdMap, poolInfo.color = v elif k == 'Color': poolInfo.textColor = v - + elif k == 'diffConstant': + poolId.diffConst = float(v) + elif k == 'motorConstant': + poolId.motorConst = float(v) specInfoMap[sId] = { "Mpath": poolId, "const": constant, @@ -1220,7 +1280,6 @@ def createSpecies(basePath, model, comptSbmlidMooseIdMap, return (True," ") - def transformUnit(unitForObject, hasonlySubUnit=False): # print "unit # ",UnitDefinition.printUnits(unitForObject.getDerivedUnitDefinition()) @@ -1301,10 +1360,12 @@ def transformUnit(unitForObject, hasonlySubUnit=False): def createCompartment(basePath, model, comptSbmlidMooseIdMap): # ToDoList : Check what should be done for the spaitialdimension is 2 or # 1, area or length - #print " createCompartment ",model.getNumCompartments() + cmptAnnotaInfo = {} + if not(model.getNumCompartments()): - return False, "Model has no compartment, atleast one compartment should exist to display the widget" + return False, "Model has no compartment, atleast one compartment should exist to display in the widget" else: + endo_surr = {} for c in range(0, model.getNumCompartments()): compt = model.getCompartment(c) # print("Compartment " + str(c) + ": "+ UnitDefinition.printUnits(compt.getDerivedUnitDefinition())) @@ -1333,18 +1394,44 @@ def createCompartment(basePath, model, comptSbmlidMooseIdMap): unitfactor, unitset, unittype = transformUnit(compt) else: - print( - " Currently we don't deal with spatial Dimension less than 3 and unit's area or length") - return False + return False," Currently we don't deal with spatial Dimension less than 3 and unit's area or length" if not(name): name = sbmlCmptId + cmptAnnotaInfo = {} + cmptAnnotaInfo = getCmptAnnotation(compt) + if "Mesh" in cmptAnnotaInfo.keys(): + if cmptAnnotaInfo["Mesh"] == "CubeMesh" or cmptAnnotaInfo["Mesh"] == "NeuroMesh": + mooseCmptId = moose.CubeMesh(basePath.path + '/' + name) + + elif cmptAnnotaInfo["Mesh"] == "CylMesh": + mooseCmptId = moose.CylMesh(basePath.path + '/' + name) + ln = (float(cmptAnnotaInfo["totLength"])/float(cmptAnnotaInfo["diffLength"]))*float(cmptAnnotaInfo["diffLength"]) + mooseCmptId.x1 = ln + mooseCmptId.diffLength = float(cmptAnnotaInfo["diffLength"]) + + elif cmptAnnotaInfo["Mesh"] == "EndoMesh": + mooseCmptId = moose.EndoMesh(basePath.path + '/' + name) + endo_surr[sbmlCmptId] = cmptAnnotaInfo["surround"] - mooseCmptId = moose.CubeMesh(basePath.path + '/' + name) + if cmptAnnotaInfo["isMembraneBound"] == 'True': + mooseCmptId.isMembraneBound = bool(cmptAnnotaInfo["isMembraneBound"]) + else: + mooseCmptId = moose.CubeMesh(basePath.path+'/'+name) + mooseCmptId.volume = (msize * unitfactor) + comptSbmlidMooseIdMap[sbmlCmptId] = { "MooseId": mooseCmptId, "spatialDim": dimension, "size": msize} - return True + + for key,value in endo_surr.items(): + if value in comptSbmlidMooseIdMap: + endomesh = comptSbmlidMooseIdMap[key]["MooseId"] + endomesh.surround = comptSbmlidMooseIdMap[value]["MooseId"] + elif key in comptSbmlidMooseIdMap: + del(comptSbmlidMooseIdMap[key]) + return False," EndoMesh's surrounding compartment missing or wrong deleting the compartment check the file" + return True,"" def setupMMEnzymeReaction(reac, rName, specInfoMap, reactSBMLIdMooseId, diff --git a/python/moose/SBML/writeSBML.py b/python/moose/SBML/writeSBML.py index a3d898d4..d8325ee2 100644 --- a/python/moose/SBML/writeSBML.py +++ b/python/moose/SBML/writeSBML.py @@ -13,11 +13,20 @@ ** copyright (C) 2003-2017 Upinder S. Bhalla. and NCBS Created : Friday May 27 12:19:00 2016(+0530) Version -Last-Updated: Mon 30 Apr 15:10:00 2018(+0530) +Last-Updated: Tue 3 Dec 15:15:10 2018(+0530) By: HarshaRani **********************************************************************/ /**************************** 2018 +Dec 07: using fixXreac's restoreXreacs function to remove xfer +Dec 03: add diff and motor constants to pool +Nov 30: group id is changed from name to moose_id and group.name is added along with annotation for group listing +Nov 22: searched for _xfer_ instead of xfer +Nov 12: xfer cross compartment molecules are not written to SBML instead written the original molecule also for connecting Reaction and Enzyme +Nov 06: All the Mesh Cyl,Cube,Neuro,Endo Mesh's can be written into SBML format with annotation field where Meshtype\ + numDiffCompts,isMembraneBound and surround are written out. + For EndoMesh check made to see surround is specified +Oct 20: EndoMesh added to SBML Oct 16: CylMesh's comparment volume is written, but zeroth volex details are populated Oct 13: CylMesh are written to SBML with annotation field and only zeroth element/voxel (incase of cylMesh) of moose object is written Oct 1 : corrected the spell of CyclMesh-->CylMesh, negating the yaxis for kkit is removed @@ -40,6 +49,7 @@ import moose from moose.SBML.validation import validateModel from moose.chemUtil.chemConnectUtil import * from moose.chemUtil.graphUtils import * +from moose.fixXreacs import restoreXreacs foundLibSBML_ = False try: @@ -76,6 +86,7 @@ def mooseWriteSBML(modelpath, filename, sceneitems={}): if not moose.exists(modelpath): return False, "Path doesn't exist" elif moose.exists(modelpath): + moose.fixXreacs.restoreXreacs(modelpath) checkCompt = moose.wildcardFind(modelpath+'/##[0][ISA=ChemCompt]') mObj = moose.wildcardFind(moose.element(modelpath).path+'/##[0][ISA=PoolBase]'+','+ @@ -108,6 +119,7 @@ def mooseWriteSBML(modelpath, filename, sceneitems={}): neutralNotes = "" specieslist = moose.wildcardFind(modelpath + '/##[0][ISA=PoolBase]') + if specieslist: neutralPath = getGroupinfo(specieslist[0]) if moose.exists(neutralPath.path + '/info'): @@ -124,11 +136,12 @@ def mooseWriteSBML(modelpath, filename, sceneitems={}): writeUnits(cremodel_) modelAnno = writeSimulationAnnotation(modelpath) + if modelAnno: cremodel_.setAnnotation(modelAnno) groupInfo = {} - - compartexist, groupInfo = writeCompt(modelpath, cremodel_) + compterrors ="" + compartexist, groupInfo,compterrors = writeCompt(modelpath, cremodel_) if compartexist == True: species = writeSpecies( modelpath,cremodel_,sbmlDoc,sceneitems,groupInfo) @@ -145,20 +158,24 @@ def mooseWriteSBML(modelpath, filename, sceneitems={}): mplugin = cremodel_.getPlugin("groups") group = mplugin.createGroup() name = str(idBeginWith(moose.element(key).name)) - group.setId(name) + moosegrpId = name +"_" + str(moose.element(key).getId().value) + "_" + str(moose.element(key).getDataIndex()) + group.setId(moosegrpId) + group.setName(name) + group.setKind("collection") if moose.exists(key.path+'/info'): ginfo = moose.element(key.path+'/info') else: ginfo = moose.Annotator(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) + grpAnno = "<moose:GroupAnnotation>" + grpAnno = grpAnno + "<moose:Compartment>" + groupCompartment.name + "</moose:Compartment>\n" + if moose.element(key.parent).className == "Neutral": + grpAnno = grpAnno + "<moose:Group>" + key.parent.name + "</moose:Group>\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() @@ -170,13 +187,16 @@ def mooseWriteSBML(modelpath, filename, sceneitems={}): writeTofile = filepath + "/" + filename + '.xml' writeSBMLToFile(sbmlDoc, writeTofile) return True, consistencyMessages, writeTofile - + if (not SBMLok): #cerr << "Errors encountered " << endl consistencyMessages = "Errors encountered" return -1, consistencyMessages else: - return False, "Atleast one compartment should exist to write SBML" + if compterrors: + return False, compterrors + else: + return False,"Atleast one compartment should exist to write SBML" def writeEnz(modelpath, cremodel_, sceneitems,groupInfo): for enz in moose.wildcardFind(modelpath + '/##[0][ISA=EnzBase]'): @@ -595,6 +615,15 @@ def processRateLaw(objectCount, cremodel, noofObj, type, mobjEnz): nameList_[:] = [] for value, count in objectCount.items(): value = moose.element(value) + ''' + if re.search("_xfer_",value.name): + modelRoot = value.path[0:value.path.index('/',1)] + xrefPool = value.name[:value.name.index("_xfer_")] + xrefCompt = value.name[value.name.index("_xfer_") + len("_xfer_"):] + orgCompt = moose.wildcardFind(modelRoot+'/##[FIELD(name)='+xrefCompt+']')[0] + orgPool = moose.wildcardFind(orgCompt.path+'/##[FIELD(name)='+xrefPool+']')[0] + value = orgPool + ''' nameIndex = value.name + "_" + \ str(value.getId().value) + "_" + str(value.getDataIndex()) + "_" clean_name = (str(idBeginWith(convertSpecialChar(nameIndex)))) @@ -836,7 +865,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", "CubeMesh", "CylMesh"]): + while not mooseIsInstance(element, ["Neutral", "CubeMesh", "CylMesh","EndoMesh","NeuroMesh"]): element = element.parent return element @@ -848,7 +877,7 @@ def idBeginWith(name): return changedName def findGroup_compt(melement): - while not (mooseIsInstance(melement, ["Neutral","CubeMesh", "CylMesh"])): + while not (mooseIsInstance(melement, ["Neutral","CubeMesh", "CylMesh","EndoMesh","NeuroMesh"])): melement = melement.parent return melement @@ -878,82 +907,82 @@ def convertSpecialChar(str1): def writeSpecies(modelpath, cremodel_, sbmlDoc, sceneitems,speGroup): # getting all the species for spe in moose.wildcardFind(modelpath + '/##[0][ISA=PoolBase]'): - sName = convertSpecialChar(spe.name) - comptVec = findCompartment(spe) - speciannoexist = False - speciGpname = "" - - if not isinstance(moose.element(comptVec), moose.ChemCompt): - return -2 - else: - compt = comptVec.name + "_" + \ - str(comptVec.getId().value) + "_" + \ - str(comptVec.getDataIndex()) + "_" - s1 = cremodel_.createSpecies() - spename = sName + "_" + \ - str(spe.getId().value) + "_" + str(spe.getDataIndex()) + "_" - spename = str(idBeginWith(spename)) - s1.setId(spename) - - if spename.find( - "cplx") != -1 and isinstance(moose.element(spe.parent), moose.EnzBase): - enz = spe.parent - if (moose.element(enz.parent), moose.PoolBase): - # print " found a cplx name ",spe.parent, - # moose.element(spe.parent).parent - enzname = enz.name - enzPool = (enz.parent).name - sName = convertSpecialChar( - enzPool + "_" + enzname + "_" + sName) - - #s1.setName(sName) - s1.setName(str(idBeginWith(convertSpecialCharshot(spe.name)))) - # s1.setInitialAmount(spe.nInit) - s1.setInitialConcentration(spe.concInit) - s1.setCompartment(compt) - # Setting BoundaryCondition and constant as per this rule for BufPool - # -constanst -boundaryCondition -has assignment/rate Rule -can be part of sub/prd - # false true yes yes - # true true no yes - if spe.className == "BufPool" or spe.className == "ZombieBufPool": - # BoundaryCondition is made for buff pool - s1.setBoundaryCondition(True) - - if moose.exists(spe.path + '/func'): - bpf = moose.element(spe.path) - for fp in bpf.children: - if fp.className == "Function" or fp.className == "ZombieFunction": - if len(moose.element( - fp.path + '/x').neighbors["input"]) > 0: - s1.setConstant(False) - else: - # if function exist but sumtotal object doesn't - # exist - spe_constTrue.append(spename) - s1.setConstant(True) - else: - spe_constTrue.append(spename) - s1.setConstant(True) + #Eliminating xfer molecules writting + if not re.search("_xfer_",spe.name): + + sName = convertSpecialChar(spe.name) + comptVec = findCompartment(spe) + speciannoexist = False + + if not isinstance(moose.element(comptVec), moose.ChemCompt): + return -2 else: - # if not bufpool then Pool, then - s1.setBoundaryCondition(False) - s1.setConstant(False) - s1.setUnits("substance") - s1.setHasOnlySubstanceUnits(False) - if moose.exists(spe.path + '/info'): - Anno = moose.Annotator(spe.path + '/info') - if Anno.notes != "": - cleanNotesS = convertNotesSpecialChar(Anno.notes) - notesStringS = "<body xmlns=\"http://www.w3.org/1999/xhtml\">\n \t \t" + \ - cleanNotesS + "\n\t </body>" - s1.setNotes(notesStringS) - - - element = moose.element(spe) - ele = getGroupinfo(element) - if element.className == "Neutral" or Anno.color or Anno.textColor or sceneitems or Anno.x or Anno.y: - speciannoexist = True - if speciannoexist: + compt = comptVec.name + "_" + \ + str(comptVec.getId().value) + "_" + \ + str(comptVec.getDataIndex()) + "_" + s1 = cremodel_.createSpecies() + spename = sName + "_" + \ + str(spe.getId().value) + "_" + str(spe.getDataIndex()) + "_" + spename = str(idBeginWith(spename)) + s1.setId(spename) + + if spename.find( + "cplx") != -1 and isinstance(moose.element(spe.parent), moose.EnzBase): + enz = spe.parent + if (moose.element(enz.parent), moose.PoolBase): + # print " found a cplx name ",spe.parent, + # moose.element(spe.parent).parent + enzname = enz.name + enzPool = (enz.parent).name + sName = convertSpecialChar( + enzPool + "_" + enzname + "_" + sName) + + #s1.setName(sName) + s1.setName(str(idBeginWith(convertSpecialCharshot(spe.name)))) + # s1.setInitialAmount(spe.nInit) + s1.setInitialConcentration(spe.concInit) + s1.setCompartment(compt) + # Setting BoundaryCondition and constant as per this rule for BufPool + # -constanst -boundaryCondition -has assignment/rate Rule -can be part of sub/prd + # false true yes yes + # true true no yes + if spe.className == "BufPool" or spe.className == "ZombieBufPool": + # BoundaryCondition is made for buff pool + s1.setBoundaryCondition(True) + + if moose.exists(spe.path + '/func'): + bpf = moose.element(spe.path) + for fp in bpf.children: + if fp.className == "Function" or fp.className == "ZombieFunction": + if len(moose.element( + fp.path + '/x').neighbors["input"]) > 0: + s1.setConstant(False) + else: + # if function exist but sumtotal object doesn't + # exist + spe_constTrue.append(spename) + s1.setConstant(True) + else: + spe_constTrue.append(spename) + s1.setConstant(True) + else: + # if not bufpool then Pool, then + s1.setBoundaryCondition(False) + s1.setConstant(False) + s1.setUnits("substance") + s1.setHasOnlySubstanceUnits(False) + if moose.exists(spe.path + '/info'): + Anno = moose.Annotator(spe.path + '/info') + if Anno.notes != "": + cleanNotesS = convertNotesSpecialChar(Anno.notes) + notesStringS = "<body xmlns=\"http://www.w3.org/1999/xhtml\">\n \t \t" + \ + cleanNotesS + "\n\t </body>" + s1.setNotes(notesStringS) + + + element = moose.element(spe) + ele = getGroupinfo(element) + speciAnno = "<moose:ModelAnnotation>\n" if ele.className == "Neutral": #speciAnno = speciAnno + "<moose:Group>" + ele.name + "</moose:Group>\n" @@ -982,6 +1011,8 @@ def writeSpecies(modelpath, cremodel_, sbmlDoc, sceneitems,speGroup): if Anno.textColor: speciAnno = speciAnno + "<moose:textColor>" + \ Anno.textColor + "</moose:textColor>\n" + speciAnno = speciAnno + "<moose:diffConstant>" + str(spe.diffConst) + "</moose:diffConstant>\n" + speciAnno = speciAnno + "<moose:motorConstant>" + str(spe.motorConst)+ "</moose:motorConstant>\n" speciAnno = speciAnno + "</moose:ModelAnnotation>" s1.setAnnotation(speciAnno) return True @@ -991,49 +1022,85 @@ def writeCompt(modelpath, cremodel_): # getting all the compartments compts = moose.wildcardFind(modelpath + '/##[0][ISA=ChemCompt]') groupInfo = {} + comptID_sbml = {} for compt in compts: comptAnno = "" comptName = convertSpecialChar(compt.name) # converting m3 to litre - if isinstance(compt,moose.CylMesh): + createCompt = True + size = compt.volume * pow(10, 3) + ndim = compt.numDimensions + csetId = (str(idBeginWith(comptName + + "_" + + str(compt.getId().value) + + "_" + + str(compt.getDataIndex()) + + "_"))) + comptID_sbml[compt] = csetId + if isinstance(compt,moose.EndoMesh): + if comptID_sbml.get(compt.surround) == None: + createCompt = False + return False,groupInfo,"Outer compartment need to be specified for EndoMesh " + #return " EndoMesh need to outer compartment to be specified " + else: + comptAnno = "<moose:CompartmentAnnotation><moose:Mesh>" + \ + str(compt.className) + "</moose:Mesh>\n" + \ + "<moose:surround>" + \ + str(comptID_sbml[compt.surround])+ "</moose:surround>\n" + \ + "<moose:isMembraneBound>" + \ + str(compt.isMembraneBound)+ "</moose:isMembraneBound>\n" + \ + "</moose:CompartmentAnnotation>" + elif isinstance (compt,moose.CylMesh) : size = (compt.volume/compt.numDiffCompts)*pow(10,3) comptAnno = "<moose:CompartmentAnnotation><moose:Mesh>" + \ str(compt.className) + "</moose:Mesh>\n" + \ - "<moose:numDiffCompts>" + \ - str(compt.numDiffCompts)+ "</moose:numDiffCompts>\n" + \ + "<moose:totLength>" + \ + str(compt.totLength)+ "</moose:totLength>\n" + \ + "<moose:diffLength>" + \ + str(compt.diffLength)+ "</moose:diffLength>\n" + \ + "<moose:isMembraneBound>" + \ + str(compt.isMembraneBound)+ "</moose:isMembraneBound>\n" + \ "</moose:CompartmentAnnotation>" - else: - size = compt.volume * pow(10, 3) - ndim = compt.numDimensions - c1 = cremodel_.createCompartment() - if comptAnno: - c1.setAnnotation(comptAnno) - c1.setId(str(idBeginWith(comptName + - "_" + - str(compt.getId().value) + - "_" + - str(compt.getDataIndex()) + - "_"))) - c1.setName(comptName) - c1.setConstant(True) - c1.setSize(compt.volume*pow(10,3)) - #c1.setSize(size) - c1.setSpatialDimensions(ndim) - c1.setUnits('volume') - #For each compartment get groups information along - for grp in moose.wildcardFind(compt.path+'/##[0][TYPE=Neutral]'): - grp_cmpt = findGroup_compt(grp.parent) - try: - value = groupInfo[moose.element(grp)] - except KeyError: - # Grp is not present - groupInfo[moose.element(grp)] = [] - + else: + comptAnno = "<moose:CompartmentAnnotation><moose:Mesh>" + \ + str(compt.className) + "</moose:Mesh>\n" + \ + "<moose:isMembraneBound>" + \ + str(compt.isMembraneBound)+ "</moose:isMembraneBound>\n" + \ + "</moose:CompartmentAnnotation>" + if createCompt: + c1 = cremodel_.createCompartment() + c1.setId(csetId) + c1.setName(comptName) + c1.setConstant(True) + c1.setSize(compt.volume*pow(10,3)) + #c1.setSize(size) + if isinstance(compts,moose.EndoMesh): + c1.outside = comptID_sbml[compt.surround] + + if comptAnno: + c1.setAnnotation(comptAnno) + c1.setSpatialDimensions(ndim) + if ndim == 3: + c1.setUnits('volume') + elif ndim == 2: + c1.setUnits('area') + elif ndim == 1: + c1.setUnits('metre') + + #For each compartment get groups information along + for grp in moose.wildcardFind(compt.path+'/##[0][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,groupInfo + return True,groupInfo,"" else: - return False,groupInfo + return False,groupInfo,"" # write Simulation runtime,simdt,plotdt def writeSimulationAnnotation(modelpath): @@ -1061,7 +1128,9 @@ def writeSimulationAnnotation(modelpath): ori = q.path name = convertSpecialChar(q.name) graphSpefound = False - while not(isinstance(moose.element(q), moose.CubeMesh) or isinstance(moose.element(q),moose.CylMesh)): + + while not(isinstance(moose.element(q), moose.CubeMesh) or isinstance(moose.element(q),moose.CylMesh) \ + or isinstance(moose.element(q), moose.EndoMesh) or isinstance(moose.element(q),moose.NeuroMesh)): q = q.parent graphSpefound = True if graphSpefound: @@ -1076,6 +1145,7 @@ def writeSimulationAnnotation(modelpath): if plots != " ": modelAnno = modelAnno + "<moose:plots> " + plots + "</moose:plots>\n" modelAnno = modelAnno + "</moose:ModelAnnotation>" + return modelAnno def recalculatecoordinates(modelpath, mObjlist,xcord,ycord): diff --git a/python/moose/__init__.py b/python/moose/__init__.py index 407b6950..3c398033 100644 --- a/python/moose/__init__.py +++ b/python/moose/__init__.py @@ -1,13 +1,18 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function -# Bring everything from moose.py to global namespace. -from moose.moose import * +# Use this format in all logger inside logger. Define it before any moose +# related module is imported. +LOGGING_FORMAT = '%(asctime)s %(message)s' # Bring everything from c++ module to global namespace. Not everything is # imported by the pervios import statement. from moose._moose import * +# Bring everything from moose.py to global namespace. +# IMP: It will overwrite any c++ function with the same name. +from moose.moose import * +from moose.server import * + # create a shorthand for version() call here. __version__ = version() - diff --git a/python/moose/chemMerge/merge.py b/python/moose/chemMerge/merge.py index 6b37ae44..d3724c8c 100644 --- a/python/moose/chemMerge/merge.py +++ b/python/moose/chemMerge/merge.py @@ -144,17 +144,17 @@ def mergeChemModel(src,des): poolListinb = {} poolListinb = updatePoolList(comptBdict) - R_Duplicated, R_Notcopiedyet,R_Daggling = [], [], [] - E_Duplicated, E_Notcopiedyet,E_Daggling = [], [], [] + R_Duplicated, R_Notcopiedyet,R_Dangling = [], [], [] + E_Duplicated, E_Notcopiedyet,E_Dangling = [], [], [] for key in list(dictComptA.keys()): funcExist, funcNotallowed = [], [] funcExist,funcNotallowed = functionMerge(dictComptB,dictComptA,key) poolListinb = updatePoolList(dictComptB) - R_Duplicated,R_Notcopiedyet,R_Daggling = reacMerge(dictComptA,dictComptB,key,poolListinb) + R_Duplicated,R_Notcopiedyet,R_Dangling = reacMerge(dictComptA,dictComptB,key,poolListinb) poolListinb = updatePoolList(dictComptB) - E_Duplicated,E_Notcopiedyet,E_Daggling = enzymeMerge(dictComptB,dictComptA,key,poolListinb) + E_Duplicated,E_Notcopiedyet,E_Dangling = enzymeMerge(dictComptB,dictComptA,key,poolListinb) # if isinstance(src, str): # if os.path.isfile(src) == True: @@ -209,15 +209,15 @@ def mergeChemModel(src,des): for ed in list(E_Notcopiedyet): print ("%s " %str(ed.name)) - if R_Daggling or E_Daggling: - print ("\n Daggling reaction/enzyme are not allowed in moose, these are not merged to %s from %s" %(dfile, sfile)) - if R_Daggling: + if R_Dangling or E_Dangling: + print ("\n Dangling reaction/enzyme are not allowed in moose, these are not merged to %s from %s" %(dfile, sfile)) + if R_Dangling: print("Reaction: ") - for rd in list(R_Daggling): + for rd in list(R_Dangling): print ("%s " %str(rd.name)) - if E_Daggling: + if E_Dangling: print ("Enzyme:") - for ed in list(E_Daggling): + for ed in list(E_Dangling): print ("%s " %str(ed.name)) ## Model is saved @@ -436,7 +436,7 @@ def copy_deleteUnlyingPoolObj(pool,path): poolcopied = moose.copy(pool,path) copied = True # deleting function and enzyme which gets copied if exist under pool - # This is done to ensure daggling function / enzyme not copied. + # This is done to ensure Dangling function / enzyme not copied. funclist = [] for types in ['setConc','setN','increment']: funclist.extend(moose.element(poolcopied).neighbors[types]) @@ -456,7 +456,7 @@ def updatePoolList(comptAdict): def enzymeMerge(comptD,comptS,key,poolListind): war_msg = "" - RE_Duplicated, RE_Notcopiedyet, RE_Daggling = [], [], [] + RE_Duplicated, RE_Notcopiedyet, RE_Dangling = [], [], [] comptDpath = moose.element(comptD[key]).path comptSpath = moose.element(comptS[key]).path objD = moose.element(comptDpath).parent.name @@ -501,7 +501,7 @@ def enzymeMerge(comptD,comptS,key,poolListind): RE_Notcopiedyet.append(es) else: # -- it is dagging reaction - RE_Daggling.append(es) + RE_Dangling.append(es) else: #Same Enzyme name # -- Same substrate and product including same volume then don't copy @@ -551,12 +551,12 @@ def enzymeMerge(comptD,comptS,key,poolListind): if eSsubname and eSprdname: RE_Notcopiedyet.append(es) else: - RE_Daggling.append(es) + RE_Dangling.append(es) - return RE_Duplicated,RE_Notcopiedyet,RE_Daggling + return RE_Duplicated,RE_Notcopiedyet,RE_Dangling def reacMerge(comptS,comptD,key,poolListina): - RE_Duplicated, RE_Notcopiedyet, RE_Daggling = [], [], [] + RE_Duplicated, RE_Notcopiedyet, RE_Dangling = [], [], [] war_msg = "" comptSpath = moose.element(comptS[key]).path comptDpath = moose.element(comptD[key]).path @@ -594,9 +594,9 @@ def reacMerge(comptS,comptD,key,poolListina): RE_Notcopiedyet.append(rs) else: # -- it is dagging reaction - RE_Daggling.append(rs) - #print ("This reaction \""+rb.path+"\" has no substrate/product daggling reaction are not copied") - #war_msg = war_msg+"\nThis reaction \""+rb.path+"\" has no substrate/product daggling reaction are not copied" + RE_Dangling.append(rs) + #print ("This reaction \""+rb.path+"\" has no substrate/product Dangling reaction are not copied") + #war_msg = war_msg+"\nThis reaction \""+rb.path+"\" has no substrate/product Dangling reaction are not copied" else: #Same reaction name @@ -640,9 +640,9 @@ def reacMerge(comptS,comptD,key,poolListina): if rSsubname and rSprdname: RE_Notcopiedyet.append(rs) else: - RE_Daggling.append(rs) + RE_Dangling.append(rs) - return RE_Duplicated,RE_Notcopiedyet,RE_Daggling + return RE_Duplicated,RE_Notcopiedyet,RE_Dangling def subprdList(reac,subprd): rtype = moose.element(reac).neighbors[subprd] diff --git a/python/moose/chemUtil/chemConnectUtil.py b/python/moose/chemUtil/chemConnectUtil.py index bbb18ed5..9c92e613 100644 --- a/python/moose/chemUtil/chemConnectUtil.py +++ b/python/moose/chemUtil/chemConnectUtil.py @@ -9,7 +9,7 @@ __version__ = "1.0.0" __maintainer__ = "Harsha Rani" __email__ = "hrani@ncbs.res.in" __status__ = "Development" -__updated__ = "Aug 8 2017" +__updated__ = "Nov 8 2018" import moose import numpy as np @@ -193,7 +193,7 @@ def countitems(mitems,objtype): def findCompartment(element): if element.path == '/': return moose.element('/') - elif mooseIsInstance(element, ["CubeMesh", "CylMesh"]): + elif mooseIsInstance(element, ["CubeMesh", "CylMesh","EndoMesh","NeuroMesh"]): return (element) else: return findCompartment(moose.element(element.parent)) diff --git a/python/moose/genesis/writeKkit.py b/python/moose/genesis/writeKkit.py index c03a77aa..7ed8d66e 100644 --- a/python/moose/genesis/writeKkit.py +++ b/python/moose/genesis/writeKkit.py @@ -9,9 +9,14 @@ __version__ = "1.0.0" __maintainer__ = "Harsha Rani" __email__ = "hrani@ncbs.res.in" __status__ = "Development" -__updated__ = "Oct 23 2018" +__updated__ = "Dec 08 2018" # 2018 +# Dec 08: using restoreXreacs from fixXreacs +# Nov 22: searched for _xfer_ instead of xfer +# Nov 21: xfer pool are not written and cleaned up if part of Reaction/Enzyme or notes, +# group are checked under all the mesh + # Oct 16: Channels are written back to genesis # only zeroth element is taken for written back to genesis, this is true for CubeMesh and CylMesh # 2017 @@ -23,7 +28,8 @@ import re import moose from moose.chemUtil.chemConnectUtil import * from moose.chemUtil.graphUtils import * - +from moose.fixXreacs import restoreXreacs + foundmatplotlib_ = False try: import matplotlib @@ -71,7 +77,7 @@ def mooseWriteKkit( modelpath, filename, sceneitems={}): global cmin,cmax,xmin,xmax,ymin,ymax cmin, xmin, ymin = 0, 0, 0 cmax, xmax, ymax = 1, 1, 1 - + moose.fixXreacs.restoreXreacs(modelpath) compt = moose.wildcardFind(modelpath+'/##[0][ISA=ChemCompt]') maxVol = estimateDefaultVol(compt) positionInfoExist = True @@ -138,6 +144,7 @@ def mooseWriteKkit( modelpath, filename, sceneitems={}): " /kinetics/#[],/kinetics/#[]/#[],/kinetics/#[]/#[]/#[][TYPE!=proto],/kinetics/#[]/#[]/#[][TYPE!=linkinfo]/##[] \"edit_elm.D <v>; drag_from_edit.w <d> <S> <x> <y> <z>\" auto 0.6\n" "simundump xtext /file/notes 0 1\n") storeReacMsg(reacList,f) + storeEnzMsg(enzList,f) storeChanMsg(chanList,f) if tgraphs: @@ -152,6 +159,7 @@ def mooseWriteKkit( modelpath, filename, sceneitems={}): return False def findMinMax(sceneitems): + cmin = 0.0 cmax = 1.0 xmin,xymin = 0.0,0.0 @@ -434,14 +442,18 @@ def trimPath(mobj): # Any moose object comes under /kinetics then one level down the path is taken. # e.g /group/poolObject or /Reac if found: - if mobj.name != "kinetics" and (mobj.className != "CubeMesh"): + if mobj.name != "kinetics":# and ( (mobj.className != "CubeMesh") and (mobj.className != "CylMesh") and (mobj.className != "EndoMesh") and (mobj.className != "NeuroMesh")): splitpath = original.path[(original.path.find(mobj.name)):len(original.path)] else: pos = original.path.find(mobj.name) + #ss = re.compile(r'\b%s\b' %mobj.name) + #a = re.search(ss, original.path) + #pos = a.start() slash = original.path.find('/',pos+1) splitpath = original.path[slash+1:len(original.path)] splitpath = re.sub("\[[0-9]+\]", "", splitpath) s = splitpath.replace("_dash_",'-') + s = splitpath.replace("_space_","_") return s # def writeSumtotal( modelpath,f): @@ -619,7 +631,6 @@ def writePool(modelpath,f,volIndex,sceneitems): color = getRandColor() if textcolor == "" or textcolor == " ": textcolor = getRandColor() - f.write("simundump kpool /kinetics/" + trimPath(p) + " 0 " + str(p.diffConst) + " " + str(0) + " " + @@ -696,13 +707,17 @@ def writeCompartment(modelpath,compts,f): i = i+1 x = xmin+4 y = ymax+1 + #geometryname = compt.name if vecIndex > 0: geometry = geometry+"simundump geometry /kinetics" + "/geometry[" + str(vecIndex) +"] 0 " + str(size) + " " + str(ndim) + " sphere " +" \"\" white black "+ str(int(x)) + " " +str(int(y)) +" 0\n"; volIndex[float(size)] = "/geometry["+str(vecIndex)+"]" + #geometry = geometry+"simundump geometry /kinetics/" + str(geometryname) + " " +str(size) + " " + str(ndim) + " sphere " +" \"\" white black " + str(int(x)) + " "+str(int(y))+ " 0\n"; + #volIndex[float(size)] = geometryname else: - + #geometry = geometry+"simundump geometry /kinetics/" + str(geometryname) + " " + str(size) + " " + str(ndim) + " sphere " +" \"\" white black " + str(int(x)) + " "+str(int(y))+ " 0\n"; geometry = geometry+"simundump geometry /kinetics" + "/geometry 0 " + str(size) + " " + str(ndim) + " sphere " +" \"\" white black " + str(int(x)) + " "+str(int(y))+ " 0\n"; volIndex[float(size)] = "/geometry" + #volIndex[float(size)] = geometryname f.write(geometry) writeGroup(modelpath,f) return volIndex @@ -787,11 +802,12 @@ def writeNotes(modelpath,f): moose.wildcardFind(modelpath+"/##[0][ISA=Function]") +\ moose.wildcardFind(modelpath+"/##[0][ISA=StimulusTable]") for item in items: - if moose.exists(item.path+'/info'): - info = item.path+'/info' - notes = moose.Annotator(info).getField('notes') - if (notes): - f.write("call /kinetics/"+ trimPath(item)+"/notes LOAD \ \n\""+moose.Annotator(info).getField('notes')+"\"\n") + if not re.search("xfer",item.name): + if moose.exists(item.path+'/info'): + info = item.path+'/info' + notes = moose.Annotator(info).getField('notes') + if (notes): + f.write("call /kinetics/"+ trimPath(item)+"/notes LOAD \ \n\""+moose.Annotator(info).getField('notes')+"\"\n") def writeFooter1(f): f.write("\nenddump\n // End of dump\n") diff --git a/python/moose/moose.py b/python/moose/moose.py index a55bc7be..c3c6b60d 100644 --- a/python/moose/moose.py +++ b/python/moose/moose.py @@ -1,20 +1,17 @@ # -*- coding: utf-8 -*- -from __future__ import print_function, division, absolute_import - # Author: Subhasis Ray # Maintainer: Dilawar Singh, Harsha Rani, Upi Bhalla +from __future__ import print_function, division, absolute_import import warnings +import os import pydoc -import moose -import moose.utils as mu from io import StringIO -from os.path import splitext from contextlib import closing # Import function from C++ module into moose namespace. -# from moose._moose import * import moose._moose as _moose +import moose.utils as mu # sbml import. sbmlImport_, sbmlError_ = True, '' @@ -60,40 +57,58 @@ except Exception as e: mergechemImport_ = False mergechemError_ = '%s' % e -def loadModel(filename, target,method=None): - solverClass = 'Neutral' - if method != None: - solverClass = method - try: - f = open(filename,'r') - f.close() - except IOError as e: - print (e) - return - else: - file_name,extension = splitext(filename) - if extension in [".swc",".p"]: - ret = moose._moose.loadModel(filename,target,"Neutral") - elif extension in [".g",".cspace"]: - #only if genesis or cspace file, then mooseAddChemSolver is called - ret = moose._moose.loadModel(filename,target,"ee") - +def loadModel(filename, modelpath, solverclass="gsl"): + """loadModel: Load model from a file to a specified path. + + Parameters + ---------- + filename: str + model description file. + modelpath: str + moose path for the top level element of the model to be created. + method: str + solver type to be used for simulating the model. + TODO: Link to detailed description of solvers? + + Returns + ------- + object + 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 ) + return None + + extension = os.path.splitext(filename)[1] + if extension in [".swc", ".p"]: + 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"]: + method = "gssa" + elif sc in ["gsl","runge kutta","deterministic","ksolve","rungekutta","rk5","rkf","rk"]: + method = "gsl" + elif sc in ["exponential euler","exponentialeuler","neutral"]: + method = "ee" + else: method = "ee" - if solverClass.lower() in ["gssa","gillespie","stochastic","gsolve"]: - method = "gssa" - elif solverClass.lower() in ["gsl","runge kutta","deterministic","ksolve","rungekutta","rk5","rkf","rk"]: - method = "gsl" - elif solverClass.lower() in ["exponential euler","exponentialeuler","neutral"]: - method = "ee" - - if method != 'ee': - chemError_ = _chemUtil.add_Delete_ChemicalSolver.mooseAddChemSolver(target,method) + + if method != 'ee': + chemError = _chemUtil.add_Delete_ChemicalSolver.mooseAddChemSolver(modelpath, method) return ret + else: + mu.error( "Unknown model extenstion '%s'" % extension) + return None # Version def version( ): # Show user version. - return moose._moose.VERSION + return _moose.VERSION # Tests from moose.moose_test import test @@ -125,36 +140,42 @@ known_types = ['void', def mooseReadSBML(filepath, loadpath, solver='ee',validate="on"): """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 - + Parameter + -------- + filepath: str + filepath to be loaded. + loadpath : str + Root path for this model e.g. /model/mymodel + solver : str + Solver to use (default 'ee'). + Available options are "ee", "gsl", "stochastic", "gillespie" + "rk", "deterministic" + For full list see ?? """ global sbmlImport_ if sbmlImport_: - return _readSBML.mooseReadSBML( filepath, loadpath, solver,validate ) + return _readSBML.mooseReadSBML(filepath, loadpath, solver, validate) else: print( sbmlError_ ) return False - 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 - + """mooseWriteSBML: Writes loaded model under modelpath to a file in SBML format. + + Parameters + ---------- + modelpath : str + model path in moose e.g /model/mymodel \n + filepath : str + Path of output file. \n + sceneitems : dict + UserWarning: user need not worry about this layout position is saved in + Annotation field of all the moose Object (pool,Reaction,enzyme). + If this function is called from + * GUI - the layout position of moose object is passed + * command line - NA + * if genesis/kkit model is loaded then layout position is taken from the file + * otherwise auto-coordinates is used for layout position. """ if sbmlImport_: return _writeSBML.mooseWriteSBML(modelpath, filepath, sceneitems) @@ -163,13 +184,15 @@ def mooseWriteSBML(modelpath, filepath, sceneitems={}): return False -def mooseWriteKkit(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. + Parameters + ---------- + modelpath : str + Model path in moose. + filepath : str + Path of output file. """ global kkitImport_, kkitImport_err_ if not kkitImport_: @@ -180,10 +203,14 @@ def 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) + """mooseDeleteChemSolver + deletes solver on all the compartment and its children. + + Notes + ----- + This is neccesary while created a new moose object on a pre-existing modelpath, + this should be followed by mooseAddChemSolver for add solvers on to compartment + to simulate else default is Exponential Euler (ee) """ if chemImport_: return _chemUtil.add_Delete_ChemicalSolver.mooseDeleteChemSolver(modelpath) @@ -193,15 +220,17 @@ def mooseDeleteChemSolver(modelpath): def mooseAddChemSolver(modelpath, solver): - """ Add solver on chemical compartment and its children for calculation - - keyword arguments:\n + """mooseAddChemSolver: + Add solver on chemical compartment and its children for calculation - modelpath -- model path that is loaded into moose \n - solver -- "Exponential Euler" (ee) (default), \n - "Gillespie" ("gssa"), \n - "Runge Kutta" ("gsl") + Parameters + ---------- + modelpath : str + Model path that is loaded into moose. + solver : str + Exponential Euler "ee" is default. Other options are Gillespie ("gssa"), + Runge Kutta ("gsl") etc. Link to documentation? """ if chemImport_: chemError_ = _chemUtil.add_Delete_ChemicalSolver.mooseAddChemSolver(modelpath, solver) @@ -211,9 +240,8 @@ def mooseAddChemSolver(modelpath, solver): return False def mergeChemModel(src, des): - """ Merges two chemical model, \n - File or filepath can be passed - source is merged to destination + """mergeChemModel: Merges two chemical model. + File or filepath can be passed source is merged to destination """ #global mergechemImport_ if mergechemImport_: @@ -281,7 +309,6 @@ def le(el=None): ce = _moose.setCwe # ce is a GENESIS shorthand for change element. - def syncDataHandler(target): """Synchronize data handlers for target. @@ -360,7 +387,6 @@ def showfield(el, field='*', showtype=False): def showfields(el, showtype=False): """Convenience function. Should be deprecated if nobody uses it. - """ warnings.warn( 'Deprecated. Use showfield(element, field="*", showtype=True) instead.', @@ -374,7 +400,6 @@ finfotypes = [('valueFinfo', 'value field'), ('sharedFinfo', 'shared message field'), ('lookupFinfo', 'lookup field')] - def listmsg(el): """Return a list containing the incoming and outgoing messages of `el`. @@ -627,7 +652,3 @@ def doc(arg, inherited=True, paged=True): pager(text) else: print(text) - - -# -# moose.py ends here diff --git a/python/moose/neuroml2/reader.py b/python/moose/neuroml2/reader.py index 2f2e2d85..1629e6de 100644 --- a/python/moose/neuroml2/reader.py +++ b/python/moose/neuroml2/reader.py @@ -1,37 +1,71 @@ # -*- coding: utf-8 -*- from __future__ import print_function, division, absolute_import -# reader.py --- -# -# Filename: reader.py -# Description: +# Description: NeuroML2 reader. +# Implementation of reader for NeuroML 2 models. +# TODO: handle morphologies of more than one segment... # Author: Subhasis Ray, Padraig Gleeson -# Maintainer: +# Maintainer: Dilawar Singh <dilawars@ncbs.res.in> # Created: Wed Jul 24 15:55:54 2013 (+0530) -# Version: -# Last-Updated: 15 Jan 2018, pgleeson -# 16 Jan 2018, dilawar, python3 compatible imports. -# +# Notes: +# For update/log, please see git-blame documentation or browse the github +# repo https://github.com/BhallaLab/moose-core -"""Implementation of reader for NeuroML 2 models. -TODO: handle morphologies of more than one segment... -""" try: from future_builtins import zip, map -except ImportError: +except ImportError as e: pass -import sys import os import math import numpy as np -import neuroml as nml -from pyneuroml import pynml import moose -import moose.utils as mu -from .units import SI +import logging +logging.basicConfig( format=moose.LOGGING_FORMAT ) +logger_ = logging.getLogger(__name__) + +import moose +import neuroml as nml +import pyneuroml.pynml as pynml +from moose.neuroml2.units import SI + +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 _gates_sorted( all_gates ): + """_gates_sorted + + 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. + """ + 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 = [ ] @@ -40,31 +74,58 @@ def _unique( ls ): res.append( l ) return res -def sarea(comp): - """ - Return the surface area of compartment from length and - diameter. +def _isConcDep(ct): + """_isConcDep + Check if componet is dependant on concentration. Most HHGates are + dependant on voltage. - Parameters - ---------- - comp : Compartment instance. + :param ct: ComponentType + :type ct: nml.ComponentType + + :return: True if Component is depenant on conc, False otherwise. + """ + if 'ConcDep' in ct.extends: + return True + return False + +def _findCaConcVariableName(): + """_findCaConcVariableName + 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 - Returns - ------- - s : float - surface area of `comp`. +def sarea(comp): + """sarea + Return the surface area (2Ï–rL) of compartment from length and diameter. + :param comp: Compartment instance. + :type comp: str + :return: surface area of `comp`. + :rtype: float """ if comp.length > 0: - return comp.length * comp.diameter * np.pi + return math.pi * comp.diameter * comp.length else: - return comp.diameter * comp.diameter * np.pi + return math.pi * comp.diameter * comp.diameter -def xarea(comp): +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 """ - 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 + return math.pi * (compt.diameter/2.0)**2.0 def setRa(comp, resistivity): """Calculate total raxial from specific value `resistivity`""" @@ -81,7 +142,6 @@ 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 @@ -109,8 +169,11 @@ class NML2Reader(object): creates a passive neuronal morphology `/library/Purk2M9s`. """ def __init__(self, verbose=False): + global logger_ self.lunit = 1e-6 # micron is the default length unit 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 @@ -119,9 +182,11 @@ class NML2Reader(object): 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.Neutral('/library') + self.lib = moose.element('/library') if moose.exists('/library') \ + else moose.Neutral( '/library' ) self.id_to_ionChannel = {} self._cell_to_sg = {} # nml cell to dict - the dict maps segment groups to segments + self._variables = {} self.cells_in_populations = {} self.pop_to_cell_type = {} @@ -134,27 +199,26 @@ class NML2Reader(object): self.doc = nml.loaders.read_neuroml2_file( filename, include_includes=True, verbose=self.verbose) - if self.verbose: - mu.info('Parsed NeuroML2 file: %s'% filename) self.filename = filename + + 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: 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: self.createPopulations() self.createInputs() - mu.info("Read all from %s"%filename) def _getTemperature(self): if self.network is not None: @@ -179,7 +243,7 @@ class NML2Reader(object): mpop = moose.element(ep) if moose.exists(ep) else moose.Neutral(ep) self.cells_in_populations[pop.id] ={} for i in range(pop.size): - mu.info("Creating %s/%s instances of %s under %s"%(i,pop.size,pop.component, mpop)) + 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 @@ -302,7 +366,7 @@ class NML2Reader(object): according to NeuroML2 cell `nmlcell`.""" bp = nmlcell.biophysical_properties if bp is None: - mu.info('Warning: %s in %s has no biophysical properties' % (nmlcell.id, self.filename)) + logger_.info('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) @@ -310,7 +374,7 @@ class NML2Reader(object): def importMembraneProperties(self, nmlcell, moosecell, mp): """Create the membrane properties from nmlcell in moosecell""" if self.verbose: - mu.info('Importing membrane properties') + logger_.info('Importing membrane properties') self.importCapacitances(nmlcell, moosecell, mp.specific_capacitances) self.importChannelsToCell(nmlcell, moosecell, mp) self.importInitMembPotential(nmlcell, moosecell, mp) @@ -338,8 +402,12 @@ class NML2Reader(object): def importSpecies(self, nmlcell, properties): sg_to_segments = self._cell_to_sg[nmlcell] for species in properties.species: - if (species.concentration_model is not None) and \ - (species.concentration_model.id not in self.proto_pools): + # 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) continue segments = getSegments(nmlcell, species, sg_to_segments) for seg in segments: @@ -350,22 +418,23 @@ class NML2Reader(object): """Copy the prototype pool `species` to compartment. Currently only decaying pool of Ca2+ supported""" proto_pool = None - if species.concentrationModel in self.proto_pools: - proto_pool = self.proto_pools[species.concentration_model] + concModel = species.concentration_model + if concModel in self.proto_pools: + proto_pool = self.proto_pools[concModel] else: for innerReader in self.includes.values(): - if species.concentrationModel in innerReader.proto_pools: - proto_pool = innerReader.proto_pools[species.concentrationModel] + if concModel in innerReader.proto_pools: + proto_pool = innerReader.proto_pools[concModel] break if not proto_pool: - raise Exception('No prototype pool for %s referred to by %s' % ( - species.concentration_model, species.id) - ) + msg = 'No prototype pool for %s referred to by %s' % (concModel, species.id) + logger_.error(msg) + raise RuntimeError(msg) 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.thickness) * - (0.5 * compartment.diameter - pool.thickness) + 0.5 * compartment.diameter + pool.thick) * + (0.5 * compartment.diameter - pool.thick) ) return pool @@ -383,40 +452,56 @@ class NML2Reader(object): 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': hhfit.exponential2, 'HHSigmoidRate': hhfit.sigmoid2, 'HHSigmoidVariable': hhfit.sigmoid2, - 'HHExpLinearRate': hhfit.linoid2 } + 'HHExpLinearRate': hhfit.linoid2 + } 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) - else: - for ct in self.doc.ComponentType: - if ratefn.type == ct.name: - mu.info("Using %s to evaluate rate"%ct.name) - rate = [] - for v in tab: - req_vars = {'v':'%sV'%v,'vShift':vShift,'temperature':self._getTemperature()} - vals = pynml.evaluate_component(ct, req_variables = req_vars) - 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) + + 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([]) + def importChannelsToCell(self, nmlcell, moosecell, membrane_properties): sg_to_segments = self._cell_to_sg[nmlcell] for chdens in membrane_properties.channel_densities + membrane_properties.channel_density_v_shifts: @@ -426,17 +511,17 @@ class NML2Reader(object): try: ionChannel = self.id_to_ionChannel[chdens.ion_channel] except KeyError: - mu.info('No channel with id: %s' % chdens.ion_channel) + logger_.info('No channel with id: %s' % chdens.ion_channel) continue if self.verbose: - mu.info('Setting density of channel %s in %s to %s; erev=%s (passive: %s)'%( + logger_.info('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] + # comp = self.nml_to_moose[seg] setRm(self.nml_to_moose[seg], condDensity) setEk(self.nml_to_moose[seg], erev) else: @@ -462,14 +547,14 @@ class NML2Reader(object): raise Exception('No prototype channel for %s referred to by %s' % (chdens.ion_channel, chdens.id)) if self.verbose: - mu.info('Copying %s to %s, %s; erev=%s'%(chdens.id, comp, condDensity, erev)) + logger_.info('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) for p in 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) - #mu.info(self.paths_to_chan_elements) + #logger_.info(self.paths_to_chan_elements) chan.Gbar = sarea(comp) * condDensity chan.Ek = erev moose.connect(chan, 'channel', comp, 'channel') @@ -487,16 +572,21 @@ class NML2Reader(object): assert len(chan.gate_hh_rates)<=3, "We handle only up to 3 gates in HHCHannel" if self.verbose: - mu.info('== Creating channel: %s (%s) -> %s (%s)'%(chan.id, chan.gate_hh_rates, mchan, mgates)) + logger_.info('== Creating channel: %s (%s) -> %s (%s)'%(chan.id, chan.gate_hh_rates, mchan, mgates)) all_gates = chan.gates + chan.gate_hh_rates - for ngate, mgate in zip(all_gates,mgates): + + # 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.instance + mchan.Zpower = ngate.instances mgate.min = vmin mgate.max = vmax mgate.divs = vdivs @@ -524,10 +614,9 @@ class NML2Reader(object): ngate.q10_settings.type,ngate.q10_settings) ) - if self.verbose: - mu.info(' === Gate: %s; %s; %s; %s; %s; scale=%s'% ( - ngate.id, mgate.path, mchan.Xpower, fwd, rev, q10_scale) - ) + logger_.debug('+ 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): alpha = self.calculateRateFn(fwd, vmin, vmax, vdivs) @@ -555,8 +644,7 @@ class NML2Reader(object): mgate.tableA = q10_scale * (inf / tau) mgate.tableB = q10_scale * (1 / tau) - if self.verbose: - mu.info('%s: Created %s for %s'%(self.filename,mchan.path,chan.id)) + logger_.info('%s: Created %s for %s'%(self.filename,mchan.path,chan.id)) return mchan def createPassiveChannel(self, chan): @@ -565,8 +653,7 @@ class NML2Reader(object): mchan = moose.element(epath) else: mchan = moose.Leakage(epath) - if self.verbose: - mu.info('%s: Created %s for %s'%(self.filename,mchan.path,chan.id)) + logger_.info('%s: Created %s for %s'%(self.filename,mchan.path,chan.id)) return mchan def importInputs(self, doc): @@ -586,8 +673,7 @@ class NML2Reader(object): def importIonChannels(self, doc, vmin=-150e-3, vmax=100e-3, vdivs=5000): - if self.verbose: - mu.info('%s: Importing the ion channels' % self.filename ) + logger_.info('%s: Importing the ion channels' % self.filename ) for chan in doc.ion_channel+doc.ion_channel_hhs: if chan.type == 'ionChannelHH': @@ -600,8 +686,7 @@ class NML2Reader(object): self.id_to_ionChannel[chan.id] = chan self.nml_to_moose[chan] = mchan self.proto_chans[chan.id] = mchan - if self.verbose: - mu.info( self.filename + ': Created ion channel %s for %s %s'%( + logger_.info(self.filename + ': Created ion channel %s for %s %s'%( mchan.path, chan.type, chan.id)) def importConcentrationModels(self, doc): @@ -610,18 +695,19 @@ class NML2Reader(object): def createDecayingPoolConcentrationModel(self, concModel): """Create prototype for concentration model""" - if concModel.name is not None: + 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, id)) - ca.CaBasal = SI(concModel.restingConc) - ca.tau = SI(concModel.decayConstant) - ca.thick = SI(concModel.shellThickness) + + 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 self.proto_pools[concModel.id] = ca - self.nml_to_moose[concModel.id] = ca + self.nml_to_moose[name] = ca self.moose_to_nml[ca] = concModel - mu.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/neuroml2/units.py b/python/moose/neuroml2/units.py index 795129a5..b85bf6f7 100644 --- a/python/moose/neuroml2/units.py +++ b/python/moose/neuroml2/units.py @@ -1,56 +1,13 @@ # -*- coding: utf-8 -*- -# units.py --- -# -# Filename: units.py -# Description: -# Author: -# Maintainer: -# Created: Thu Jul 25 16:30:14 2013 (+0530) -# Version: -# Last-Updated: Sat Mar 5 14:56:35 2016 (-0500) -# By: subha -# Update #: 57 -# URL: -# Keywords: -# Compatibility: -# -# - -# Commentary: -# -# -# -# - -# Change log: -# -# -# -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, Fifth -# Floor, Boston, MA 02110-1301, USA. -# -# - -# Code: - -"""Utility to create mapping from NeuroML2 unit strings (as specified +""" +Utility to create mapping from NeuroML2 unit strings (as specified in NeuroMLCoreDimensions.xml) to SI +Author: + Subhasis Ray (Please check commit history for more details). """ -from __future__ import print_function + +from __future__ import print_function, division import os import re from xml.etree import ElementTree diff --git a/python/moose/server.py b/python/moose/server.py new file mode 100644 index 00000000..400058a3 --- /dev/null +++ b/python/moose/server.py @@ -0,0 +1,320 @@ +# -*- coding: utf-8 -*- +from __future__ import print_function, division + +__author__ = "Dilawar Singh" +__copyright__ = "Copyright 2019, Dilawar Singh" +__version__ = "1.0.0" +__maintainer__ = "Dilawar Singh" +__email__ = "dilawars@ncbs.res.in" +__status__ = "Development" + +import sys +import re +import os +import time +import shutil +import socket +import signal +import tarfile +import tempfile +import threading +import datetime +import subprocess +import logging + +# setup environment variables for the streamer starts working. +os.environ['MOOSE_SOCKET_STREAMER_ADDRESS'] = 'ghevar.ncbs.res.in:31416' + +# create a logger for this server. +logging.basicConfig( + level=logging.DEBUG, + format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', + datefmt='%m-%d %H:%M', + filename='moose_server.log', + filemode='a' + ) +console = logging.StreamHandler() +console.setLevel(logging.INFO) +formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') +console.setFormatter(formatter) +_logger = logging.getLogger('') +_logger.addHandler(console) + +__all__ = [ 'serve' ] + +stop_all_ = False + +def handler(signum, frame): + global stop_all_ + _logger.info( "User terminated all processes." ) + stop_all_ = True + +signal.signal( signal.SIGINT, handler) + +def split_data( data ): + prefixLenght = 10 + return data[:prefixLenght].strip(), data[prefixLenght:] + +def execute(cmd): + popen = subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True) + for stdout_line in iter(popen.stdout.readline, ""): + yield stdout_line + popen.stdout.close() + return_code = popen.wait() + if return_code: + raise subprocess.CalledProcessError(return_code, cmd) + +def send_msg(msg, conn): + if not msg.strip(): + return False + _logger.debug( msg ) + msg = '%s>>> %s' % (socket.gethostname(), msg) + conn.sendall( b'%010d%s' % (len(msg), msg)) + +def run(cmd, conn, cwd=None): + oldCWD = os.getcwd() + if cwd is not None: + os.chdir(cwd) + _logger.debug( "Executing in %s" % os.getcwd() ) + for line in execute(cmd.split()): + send_msg(line, conn) + os.chdir(oldCWD) + +def find_files_to_run( files ): + """Any file name starting with __main is to be run.""" + toRun = [] + for f in files: + if '__main' in os.path.basename(f): + toRun.append(f) + if toRun: + return toRun + + # Then guess. + if len(files) == 1: + return files + + for f in files: + with open(f, 'r' ) as fh: + txt = fh.read() + if re.search(r'def\s+main\(', txt): + if re.search('^\s+main\(\S+?\)', txt): + toRun.append(f) + return toRun + +def recv_input(conn, size=1024): + # first 10 bytes always tell how much to read next. Make sure the submit job + # script has it + d = conn.recv(10, socket.MSG_WAITALL) + while len(d) < 10: + try: + d = conn.recv(10, socket.MSG_WAITALL) + except Exception: + _logger.error( "Error in format. First 6 bytes are size of msg." ) + continue + d, data = int(d), b'' + while len(data) < d: + data += conn.recv(d-len(data), socket.MSG_WAITALL) + return data + +def writeTarfile( data ): + tfile = os.path.join(tempfile.mkdtemp(), 'data.tar.bz2') + with open(tfile, 'wb' ) as f: + _logger.info( "Writing %d bytes to %s" % (len(data), tfile)) + f.write(data) + # Sleep for some time so that file can be written to disk. + time.sleep(0.2) + if not tarfile.is_tarfile(tfile): + _logger.warn( 'Not a valid tar file: %s' % tfile) + return None + return tfile + +def suffixMatplotlibStmt( filename ): + outfile = '%s.1.py' % filename + with open(filename, 'r') as f: + txt = f.read() + + matplotlibText = ''' +# from matplotlib.backends.backend_pdf import PdfPages +import matplotlib.pyplot as plt + +def multipage(filename, figs=None, dpi=200): + pp = PdfPages(filename) + if figs is None: + figs = [plt.figure(n) for n in plt.get_fignums()] + for fig in figs: + fig.savefig(pp, format='pdf') + pp.close() + +def saveall(prefix='results', figs=None): + if figs is None: + figs = [plt.figure(n) for n in plt.get_fignums()] + for i, fig in enumerate(figs): + fig.savefig('%s.%d.png' %(prefix,i) ) + plt.close() + +try: + # multipage("results.pdf") + saveall() +except Exception as e: + print( e ) + ''' + with open(outfile, 'w' ) as f: + f.write( txt ) + f.write( matplotlibText ) + return outfile + +def run_file(filename, conn, cwd=None): + filename = suffixMatplotlibStmt(filename) + run( "%s %s" % (sys.executable, filename), conn, cwd) + _logger.info( '.... DONE' ) + +def extract_files(tfile, to): + userFiles = [] + with tarfile.open(tfile, 'r' ) as f: + userFiles = f.getnames( ) + try: + f.extractall( to ) + except Exception as e: + _logger.warn( e) + # now check if all files have been extracted properly + success = True + for f in userFiles: + if not os.path.exists(f): + _logger.error( "File %s could not be extracted." % f ) + success = False + return userFiles + +def prepareMatplotlib( cwd ): + with open(os.path.join(cwd, 'matplotlibrc'), 'w') as f: + f.write( 'interactive : True' ) + +def send_bz2(conn, data): + data = b'%010d%s' % (len(data), data) + conn.sendall(data) + +def sendResults(tdir, conn, fromThisTime): + # Only send new files. + resdir = tempfile.mkdtemp() + resfile = os.path.join(resdir, 'results.tar.bz2') + + with tarfile.open( resfile, 'w|bz2') as tf: + for d, sd, fs in os.walk(tdir): + for f in fs: + fpath = os.path.join(d,f) + if datetime.datetime.fromtimestamp(os.path.getmtime(fpath)) > fromThisTime: + _logger.info( "Adding file %s" % f ) + tf.add(os.path.join(d, f), f) + + time.sleep(0.01) + # now send the tar file back to client + with open(resfile, 'rb' ) as f: + data = f.read() + _logger.info( 'Total bytes in result: %d' % len(data)) + send_bz2(conn, data) + shutil.rmtree(resdir) + +def simulate( tfile, conn ): + """Simulate a given tar file. + """ + tdir = os.path.dirname( tfile ) + os.chdir( tdir ) + userFiles = extract_files(tfile, tdir) + # Now simulate. + toRun = find_files_to_run(userFiles) + if len(toRun) < 1: + return 1 + prepareMatplotlib(tdir) + status, msg = 0, '' + for _file in toRun: + try: + run_file(_file, conn, tdir) + except Exception as e: + msg += str(e) + status = 1 + return status, msg + +def savePayload( conn ): + data = recv_input(conn) + tarfileName = writeTarfile(data) + return tarfileName, len(data) + +def handle_client(conn, ip, port): + isActive = True + while isActive: + tarfileName, nBytes = savePayload(conn) + if tarfileName is None: + _logger.warn( "Could not recieve data." ) + isActive = False + _logger.info( "PAYLOAD RECIEVED: %d" % nBytes ) + if not os.path.isfile(tarfileName): + send_msg("[ERROR] %s is not a valid tarfile. Retry"%tarfileName, conn) + break + startSimTime = datetime.datetime.now() + res, msg = simulate( tarfileName, conn ) + if not res: + send_msg( "Failed to run simulation: %s" % msg, conn) + isActive = False + time.sleep(0.1) + send_msg('>DONE SIMULATION', conn) + # Send results after DONE is sent. + sendResults(os.path.dirname(tarfileName), conn, startSimTime) + +def start_server( host, port, max_requests = 10 ): + global stop_all_ + soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + soc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + try: + soc.bind( (host, port)) + _logger.info( "Server created %s:%s" %(host,port) ) + except Exception as e: + _logger.error( "Failed to bind: %s" % e) + quit(1) + + # listen upto 100 of requests + soc.listen(max_requests) + while True: + conn, (ip, port) = soc.accept() + _logger.info( "Connected with %s:%s" % (ip, port) ) + try: + t = threading.Thread(target=handle_client, args=(conn, ip, port)) + t.start() + except Exception as e: + _logger.warn(e) + if stop_all_: + break + soc.close() + +def serve(host, port): + start_server(host, port) + +def main( args ): + global stop_all_ + host, port = args.host, args.port + try: + serve(host, port) + except KeyboardInterrupt: + stop_all_ = True + quit(1) + +if __name__ == '__main__': + import argparse + # Argument parser. + description = '''Run MOOSE server.''' + parser = argparse.ArgumentParser(description=description, add_help=False) + parser.add_argument( '--help', action='help', help='Show this msg and exit') + parser.add_argument('--host', '-h' + , required = False, default = socket.gethostbyname(socket.gethostname()) + , help = 'Server Name' + ) + parser.add_argument('--port', '-p' + , required = False, default = 31417, type=int + , help = 'Port number' + ) + class Args: pass + args = Args() + parser.parse_args(namespace=args) + try: + main(args) + except KeyboardInterrupt as e: + stop_all_ = True + quit(1) diff --git a/python/rdesigneur/rdesigneur.py b/python/rdesigneur/rdesigneur.py index 6ad93d02..c1cb25ec 100644 --- a/python/rdesigneur/rdesigneur.py +++ b/python/rdesigneur/rdesigneur.py @@ -1249,7 +1249,6 @@ rdesigneur.rmoogli.updateMoogliViewer() comptList[0].name = 'dend' return comptList if not self._isModelFromKkit(): - print( "Not isModelfromKkit" ) return comptList sortedComptList = sorted( comptList, key=lambda x: -x.volume ) if self.addSomaChemCompt: @@ -1393,7 +1392,11 @@ rdesigneur.rmoogli.updateMoogliViewer() def _loadChem( self, fname, chemName ): chem = moose.Neutral( '/library/' + chemName ) - modelId = moose.loadModel( fname, chem.path, 'ee' ) + pre, ext = os.path.splitext( fname ) + if ext == '.xml' or ext == '.sbml': + modelId = moose.mooseReadSBML( fname, chem.path ) + else: + modelId = moose.loadModel( fname, chem.path, 'ee' ) comptlist = moose.wildcardFind( chem.path + '/#[ISA=ChemCompt]' ) if len( comptlist ) == 0: print("loadChem: No compartment found in file: ", fname) diff --git a/python/rdesigneur/rdesigneurProtos.py b/python/rdesigneur/rdesigneurProtos.py index cade7920..991bf4e8 100644 --- a/python/rdesigneur/rdesigneurProtos.py +++ b/python/rdesigneur/rdesigneurProtos.py @@ -239,7 +239,7 @@ def make_Ca( name ): if ( x > EREST_ACT): yA[i] = 5.0 * math.exp( -50 * (x - EREST_ACT) ) else: - yA[i] = 0.0 + yA[i] = 5.0 #yB[i] = 6.0 - yA[i] yB[i] = 5.0 x += dx @@ -336,6 +336,7 @@ def make_K_AHP( name ): K_AHP.Xpower = 0 K_AHP.Ypower = 0 K_AHP.Zpower = 1 + K_AHP.useConcentration = 1 zgate = moose.element( K_AHP.path + '/gateZ' ) xmax = 0.02 # 20 micromolar. @@ -348,7 +349,7 @@ def make_K_AHP( name ): x = zgate.min for i in range( zgate.divs + 1 ): zA[i] = min( 250.00 * CA_SCALE * x, 10 ) - zB[i] = 1.0 + zB[i] = 1.0 + zA[i] x = x + dx zgate.tableA = zA diff --git a/scheduling/Clock.cpp b/scheduling/Clock.cpp index aad5c066..dd60aecf 100644 --- a/scheduling/Clock.cpp +++ b/scheduling/Clock.cpp @@ -166,7 +166,8 @@ const Cinfo* Clock::initCinfo() ); static ReadOnlyValueFinfo< Clock, unsigned int > stride( "stride", - "Number by which the simulation advances the current step on each cycle. stride = smallest active timestep/smallest defined timestep.", + "Number by which the simulation advances the current step on each cycle. " + "stride = smallest active timestep/smallest defined timestep.", &Clock::getStride ); static ReadOnlyValueFinfo< Clock, unsigned long > currentStep( @@ -221,90 +222,90 @@ const Cinfo* Clock::initCinfo() /////////////////////////////////////////////////////// // MsgDest definitions /////////////////////////////////////////////////////// - static DestFinfo start( "start", - "Sets off the simulation for the specified duration", - new EpFunc2< Clock, double, bool >(&Clock::handleStart ) - ); - - static DestFinfo step( "step", - "Sets off the simulation for the specified # of steps. " - "Here each step advances the simulation by the timestep of the " - "smallest tick that is actually in use. ", - new EpFunc1< Clock, unsigned long >(&Clock::handleStep ) - ); - - static DestFinfo stop( "stop", - "Halts the simulation, with option to restart seamlessly", - new OpFunc0< Clock >(&Clock::stop ) - ); - - static DestFinfo reinit( "reinit", - "Zeroes out all ticks, starts at t = 0", - new EpFunc0< Clock >(&Clock::handleReinit ) - ); + static DestFinfo start( "start" + , "Sets off the simulation for the specified duration", + new EpFunc2< Clock, double, bool >(&Clock::handleStart ) + ); + + static DestFinfo step( "step" + , "Sets off the simulation for the specified # of steps. " + "Here each step advances the simulation by the timestep of the " + "smallest tick that is actually in use. " + , new EpFunc1< Clock, unsigned long >(&Clock::handleStep ) + ); + + static DestFinfo stop( "stop" + , "Halts the simulation, with option to restart seamlessly" + , new OpFunc0< Clock >(&Clock::stop ) + ); + + static DestFinfo reinit( "reinit" + , "Zeroes out all ticks, starts at t = 0" + , new EpFunc0< Clock >(&Clock::handleReinit ) + ); static Finfo* clockControlFinfos[] = { &start, &step, &stop, &reinit, }; + /////////////////////////////////////////////////////// // SharedFinfo for Shell to control Clock - /////////////////////////////////////////////////////// - static SharedFinfo clockControl( "clockControl", - "Controls all scheduling aspects of Clock, usually from Shell", - clockControlFinfos, - sizeof( clockControlFinfos ) / sizeof( Finfo* ) - ); + static SharedFinfo clockControl( "clockControl" + , "Controls all scheduling aspects of Clock, usually from Shell" + , clockControlFinfos + , sizeof( clockControlFinfos ) / sizeof( Finfo* ) + ); static Finfo* clockFinfos[] = { // Fields - &dt, // Value - &runTime, // ReadOnlyValue - ¤tTime, // ReadOnlyValue - &nsteps, // ReadOnlyValue - &numTicks, // ReadOnlyValue - &stride, // ReadOnlyValue - ¤tStep, // ReadOnlyValue - &dts, // ReadOnlyValue - &isRunning, // ReadOnlyValue - &tickStep, // LookupValue - &tickDt, // LookupValue - &defaultTick, // ReadOnlyLookupValue - &clockControl, // Shared - finished(), // Src - procs[0], // Src - procs[1], // Src - procs[2], // Src - procs[3], // Src - procs[4], // Src - procs[5], // Src - procs[6], // Src - procs[7], // Src - procs[8], // Src - procs[9], // Src - procs[10], // Src - procs[11], // Src - procs[12], // Src - procs[13], // Src - procs[14], // Src - procs[15], // Src - procs[16], // Src - procs[17], // Src - procs[18], // Src - procs[19], // Src - procs[20], // Src - procs[21], // Src - procs[22], // Src - procs[23], // Src - procs[24], // Src - procs[25], // Src - procs[26], // Src - procs[27], // Src - procs[28], // Src - procs[29], // Src - procs[30], // Src - procs[31], // Src + &dt, // Value + &runTime, // ReadOnlyValue + ¤tTime, // ReadOnlyValue + &nsteps, // ReadOnlyValue + &numTicks, // ReadOnlyValue + &stride, // ReadOnlyValue + ¤tStep, // ReadOnlyValue + &dts, // ReadOnlyValue + &isRunning, // ReadOnlyValue + &tickStep, // LookupValue + &tickDt, // LookupValue + &defaultTick, // ReadOnlyLookupValue + &clockControl, // Shared + finished(), // Src + procs[0], // Src + procs[1], // Src + procs[2], // Src + procs[3], // Src + procs[4], // Src + procs[5], // Src + procs[6], // Src + procs[7], // Src + procs[8], // Src + procs[9], // Src + procs[10], // Src + procs[11], // Src + procs[12], // Src + procs[13], // Src + procs[14], // Src + procs[15], // Src + procs[16], // Src + procs[17], // Src + procs[18], // Src + procs[19], // Src + procs[20], // Src + procs[21], // Src + procs[22], // Src + procs[23], // Src + procs[24], // Src + procs[25], // Src + procs[26], // Src + procs[27], // Src + procs[28], // Src + procs[29], // Src + procs[30], // Src + procs[31], // Src }; static string doc[] = @@ -348,89 +349,90 @@ const Cinfo* Clock::initCinfo() "different time-resolutions. Typically one uses tick 8 and 18.\n" "Here are the detailed mappings of class to tick.\n" " Class Tick dt \n" - " DiffAmp 0 50e-6\n" - " Interpol 0 50e-6\n" - " PIDController 0 50e-6\n" - " PulseGen 0 50e-6\n" - " StimulusTable 0 50e-6\n" - " testSched 0 50e-6\n" - " VClamp 0 50e-6\n" - " SynHandlerBase 1 50e-6\n" - " SimpleSynHandler 1 50e-6\n" - " STDPSynHandler 1 50e-6\n" + " DiffAmp 0 50e-6\n" + " Interpol 0 50e-6\n" + " PIDController 0 50e-6\n" + " PulseGen 0 50e-6\n" + " StimulusTable 0 50e-6\n" + " testSched 0 50e-6\n" + " VClamp 0 50e-6\n" + " SynHandlerBase 1 50e-6\n" + " SimpleSynHandler 1 50e-6\n" + " STDPSynHandler 1 50e-6\n" " GraupnerBrunel2012CaPlasticitySynHandler 1 50e-6\n" - " SeqSynHandler 1 50e-6\n" - " CaConc 1 50e-6\n" - " CaConcBase 1 50e-6\n" - " DifShell 1 50e-6\n" - " DifShellBase 1 50e-6\n" - " MMPump 1 50e-6\n" - " DifBuffer 1 50e-6\n" - " DifBufferBase 1 50e-6\n" - " MgBlock 1 50e-6\n" - " Nernst 1 50e-6\n" - " RandSpike 1 50e-6\n" - " ChanBase 2 50e-6\n" - " IntFire 2 50e-6\n" - " IntFireBase 2 50e-6\n" - " LIF 2 50e-6\n" - " QIF 2 50e-6\n" - " ExIF 2 50e-6\n" - " AdExIF 2 50e-6\n" - " AdThreshIF 2 50e-6\n" - " IzhIF 2 50e-6\n" - " IzhikevichNrn 2 50e-6\n" - " SynChan 2 50e-6\n" - " NMDAChan 2 50e-6\n" - " GapJunction 2 50e-6\n" - " HHChannel 2 50e-6\n" - " HHChannel2D 2 50e-6\n" - " Leakage 2 50e-6\n" - " MarkovChannel 2 50e-6\n" - " MarkovGslSolver 2 50e-6\n" - " MarkovRateTable 2 50e-6\n" - " MarkovSolver 2 50e-6\n" - " MarkovSolverBase 2 50e-6\n" - " RC 2 50e-6\n" - " Compartment (init) 3 50e-6\n" - " CompartmentBase (init ) 3 50e-6\n" - " SymCompartment (init) 3 50e-6\n" - " Compartment 4 50e-6\n" - " CompartmentBase 4 50e-6\n" - " SymCompartment 4 50e-6\n" - " SpikeGen 5 50e-6\n" - " HSolve 6 50e-6\n" - " SpikeStats 7 50e-6\n" - " Table 8 0.1e-3\n" - " TimeTable 8 0.1e-3\n" - - " Dsolve 10 0.01\n" - " Adaptor 11 0.1\n" - " Func 12 0.1\n" - " Function 12 0.1\n" - " Arith 12 0.1\n" - " BufPool 13 0.1\n" - " Pool 13 0.1\n" - " PoolBase 13 0.1\n" - " CplxEnzBase 14 0.1\n" - " Enz 14 0.1\n" - " EnzBase 14 0.1\n" - " MMenz 14 0.1\n" - " Reac 14 0.1\n" - " ReacBase 14 0.1\n" - " Gsolve (init) 15 0.1\n" - " Ksolve (init) 15 0.1\n" - " Gsolve 16 0.1\n" - " Ksolve 16 0.1\n" - " Stats 17 0.1\n" - " Table2 18 1\n" - " Streamer 19 10\n" - - " HDF5DataWriter 30 1\n" - " HDF5WriterBase 30 1\n" - " NSDFWriter 30 1\n" - " PyRun 30 1\n" - " PostMaster 31 0.01\n" + " SeqSynHandler 1 50e-6\n" + " CaConc 1 50e-6\n" + " CaConcBase 1 50e-6\n" + " DifShell 1 50e-6\n" + " DifShellBase 1 50e-6\n" + " MMPump 1 50e-6\n" + " DifBuffer 1 50e-6\n" + " DifBufferBase 1 50e-6\n" + " MgBlock 1 50e-6\n" + " Nernst 1 50e-6\n" + " RandSpike 1 50e-6\n" + " ChanBase 2 50e-6\n" + " IntFire 2 50e-6\n" + " IntFireBase 2 50e-6\n" + " LIF 2 50e-6\n" + " QIF 2 50e-6\n" + " ExIF 2 50e-6\n" + " AdExIF 2 50e-6\n" + " AdThreshIF 2 50e-6\n" + " IzhIF 2 50e-6\n" + " IzhikevichNrn 2 50e-6\n" + " SynChan 2 50e-6\n" + " NMDAChan 2 50e-6\n" + " GapJunction 2 50e-6\n" + " HHChannel 2 50e-6\n" + " HHChannel2D 2 50e-6\n" + " Leakage 2 50e-6\n" + " MarkovChannel 2 50e-6\n" + " MarkovGslSolver 2 50e-6\n" + " MarkovRateTable 2 50e-6\n" + " MarkovSolver 2 50e-6\n" + " MarkovSolverBase 2 50e-6\n" + " RC 2 50e-6\n" + " Compartment (init) 3 50e-6\n" + " CompartmentBase (init ) 3 50e-6\n" + " SymCompartment (init) 3 50e-6\n" + " Compartment 4 50e-6\n" + " CompartmentBase 4 50e-6\n" + " SymCompartment 4 50e-6\n" + " SpikeGen 5 50e-6\n" + " HSolve 6 50e-6\n" + " SpikeStats 7 50e-6\n" + " Table 8 0.1e-3\n" + " TimeTable 8 0.1e-3\n" + + " Dsolve 10 0.01\n" + " Adaptor 11 0.1\n" + " Func 12 0.1\n" + " Function 12 0.1\n" + " Arith 12 0.1\n" + " BufPool 13 0.1\n" + " Pool 13 0.1\n" + " PoolBase 13 0.1\n" + " CplxEnzBase 14 0.1\n" + " Enz 14 0.1\n" + " EnzBase 14 0.1\n" + " MMenz 14 0.1\n" + " Reac 14 0.1\n" + " ReacBase 14 0.1\n" + " Gsolve (init) 15 0.1\n" + " Ksolve (init) 15 0.1\n" + " Gsolve 16 0.1\n" + " Ksolve 16 0.1\n" + " Stats 17 0.1\n" + " Table2 18 1\n" + " SocketStreamer 19 5\n" + " Streamer 20 10\n" + + " HDF5DataWriter 30 1\n" + " HDF5WriterBase 30 1\n" + " NSDFWriter 30 1\n" + " PyRun 30 1\n" + " PostMaster 31 0.01\n" " \n" " Note that the other classes are not scheduled at all.", }; @@ -748,22 +750,22 @@ void Clock::handleStep( const Eref& e, unsigned long numSteps ) for( unsigned int i = 0; i < numThreads_; ++i ) { std::async( std::launch::async - , [this,blockSize,i,nTasks,endStep,e] + , [this,blockSize,i,nTasks,endStep,e] + { + unsigned int mapI = i * blockSize; + // Get the block we want to run in paralle. + for( unsigned int ii = i * blockSize; ii < min((i+1) * blockSize, nTasks); ii++ ) { - unsigned int mapI = i * blockSize; - // Get the block we want to run in paralle. - for( unsigned int ii = i * blockSize; ii < min((i+1) * blockSize, nTasks); ii++ ) + unsigned int j = activeTicks_[ ii ]; + if( endStep % j == 0 ) { - unsigned int j = activeTicks_[ ii ]; - if( endStep % j == 0 ) - { - info_.dt = j * dt_; - processVec( )[ activeTicksMap_[mapI] ]->send( e, &info_ ); - } - mapI++; + info_.dt = j * dt_; + processVec( )[ activeTicksMap_[mapI] ]->send( e, &info_ ); } + mapI++; } - ); + } + ); } #else vector< unsigned int >::const_iterator k = activeTicksMap_.begin(); @@ -783,13 +785,13 @@ void Clock::handleStep( const Eref& e, unsigned long numSteps ) // true. if( notify_ ) { - if( fmod(100 * currentTime_ / runTime_ , 10.0) == 0.0 ) + if( fmod(100 * currentTime_ / runTime_, 10.0) == 0.0 ) { time( &rawtime ); timeinfo = localtime( &rawtime ); strftime(now, 80, "%c", timeinfo); cout << "@ " << now << ": " << 100 * currentTime_ / runTime_ - << "% of total " << runTime_ << " seconds is over." << endl; + << "% of total " << runTime_ << " seconds is over." << endl; } } @@ -826,6 +828,7 @@ void Clock::handleReinit( const Eref& e ) info_.dt = *j * dt_; reinitVec()[*k++]->send( e, &info_ ); } + info_.dt = dt_; doingReinit_ = false; } @@ -946,7 +949,10 @@ void Clock::buildDefaultTick() defaultTick_["Stats"] = 17; defaultTick_["Table2"] = 18; - defaultTick_["Streamer"] = 19; + + defaultTick_["SocketStreamer"] = 19; + defaultTick_["Streamer"] = 20; + defaultTick_["HDF5DataWriter"] = 30; defaultTick_["HDF5WriterBase"] = 30; defaultTick_["NSDFWriter"] = 30; @@ -1013,9 +1019,9 @@ void Clock::buildDefaultTick() defaultDt_[5] = 50.0e-6; defaultDt_[6] = 50.0e-6; defaultDt_[7] = 50.0e-6; - defaultDt_[8] = 1.0e-4; // For the tables for electrical calculations - defaultDt_[9] = 0.0; // Not assigned - defaultDt_[10] = 0.01; // For diffusion. + defaultDt_[8] = 1.0e-4; // For the tables for electrical calculations + defaultDt_[9] = 0.0; // Not assigned + defaultDt_[10] = 0.01; // For diffusion. defaultDt_[11] = 0.1; defaultDt_[12] = 0.1; defaultDt_[13] = 0.1; @@ -1023,8 +1029,9 @@ void Clock::buildDefaultTick() defaultDt_[15] = 0.1; defaultDt_[16] = 0.1; defaultDt_[17] = 0.1; - defaultDt_[18] = 1; // For tables for chemical calculations. - defaultDt_[19] = 10; // For Streamer + defaultDt_[18] = 1; // For tables for chemical calculations. + defaultDt_[19] = 5; // For Socket Streamer + defaultDt_[20] = 10; // For CSV Streamer // 20-29 are not assigned. defaultDt_[30] = 1; // For the HDF writer diff --git a/scripts/Makefile.wheel b/scripts/Makefile.wheel deleted file mode 100644 index 86f50262..00000000 --- a/scripts/Makefile.wheel +++ /dev/null @@ -1,18 +0,0 @@ -all : fix - @echo "All done" - -wheel : ./setup.wheel.py - python ./setup.wheel.py bdist_wheel - -check : wheel - auditwheel show dist/*.whl - echo "If successful then run `make fix`" - -fix : check - auditwheel repair dist/*.whl - -upload : fix - twine upload dist/*.whl - - - diff --git a/scripts/Portfile b/scripts/Portfile deleted file mode 100644 index ee48c568..00000000 --- a/scripts/Portfile +++ /dev/null @@ -1,56 +0,0 @@ -# $Id$ - -PortSystem 1.0 - -name moose -version 3.0.2 -categories science -platforms darwin -maintainers dilawars \ - ncbs.res.in:dilawars -description MOOSE is the Multiscale Object-Oriented Simulation \ - Environment. -long_description MOOSE is the Multiscale Object-Oriented Simulation \ - Environment. - -homepage http://moose.ncbs.res.in -fetch.type git -fetch.ignore_sslcert yes -git.url https://github.com/BhallaLab/moose-core -git.branch master -license GPL-3 - - -depends_build port:cmake \ - port:python27 \ - port:gsl \ - port:hdf5 \ - -depends_lib port:gsl \ - port:hdf5 \ - port:py27-matplotlib \ - port:py27-numpy \ - port:python27 \ - -set python_branch 2.7 - -configure.cmd { - mkdir -p _build - cd _build - cmake -DCMAKE_INSTALL_PREFIX=${prefix} .. -} -configure.args VERBOSE=1 -configure.pre_args "" -configure.post_args "" - -build.cmd cd _build && make -build.pre_args "" -build.post_args "" - -test.cmd cd _build && ctest --output-on-failure - -##destroot.cmd cd _build && make install DESTDIR=${destdir} -##destroot.args "" -##destroot.pre_args "" -##destroot.post_args "" -##destroot.destdir prefix=${destroot}/${prefix} diff --git a/scripts/build-moose-core b/scripts/build-moose-core deleted file mode 100755 index 61d0abac..00000000 --- a/scripts/build-moose-core +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -#if one needs SBML support pass USE_SBML=1 else pass USE_SBML=0, -#if USE_SBML=1 is used make sure libSBML is installed and "libSBML-5.9.0" is currently supported - -(make clean; make USE_SBML=1) -local_site_package_directory=`python -c "import site; print site.getusersitepackages()"` -mkdir -p "$local_site_package_directory" -echo $(echo `pwd` | sed "s/\/[^\/]*$//")'/moose-core/python' > "$local_site_package_directory/moose.pth" -#echo "`pwd`/moose-core/python" > "$local_site_package_directory/moose.pth" - diff --git a/scripts/build_debian.sh b/scripts/build_debian.sh deleted file mode 100755 index f0f9247e..00000000 --- a/scripts/build_debian.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env bash -# This script is for launchpad. -( -set -e -set -o xtrace -cd .. -cat > moose.recipe <<EOF -# bzr-builder format 0.3 deb-version {debupstream}+{revno} -lp:moose -EOF -# one can do nesting here. -if [ $# -gt 0 ]; then - if [[ "$1" == "update" ]]; then - echo "Fetching repo and creating tar-ball" - bzr dailydeb --allow-fallback-to-native moose.recipe .. - elif [[ "$1" == "pbuilder" ]]; then - bzr dailydeb --allow-fallback-to-native moose.recipe .. - sudo -E pbuilder build ../*.dsc - exit - fi -fi - -tarFile=`find .. -type f -maxdepth 1 -name "moose_3.0*.tar.gz"` -echo "Found tarfiles are $tarFile" -if [[ ! $tarFile ]]; then - echo "I could not file a tar.gz file. Can't continue" - echo "++ Cleaning previous mess" - rm -rf ../moose_3.0* ../moose-{* - echo "++ Let me download a fresh one" - bzr dailydeb --allow-fallback-to-native moose.recipe .. -fi - -rm -f moose.recipe -echo "Building debian package" -bzr builddeb -- -uc -us -) diff --git a/scripts/build_debian_locally_on_ubuntu.sh b/scripts/build_debian_locally_on_ubuntu.sh deleted file mode 100755 index a7ba62b2..00000000 --- a/scripts/build_debian_locally_on_ubuntu.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash -( - cd .. - debuild -uc -us -) diff --git a/scripts/build_debian_using_bzr.sh b/scripts/build_debian_using_bzr.sh deleted file mode 100755 index f0f9247e..00000000 --- a/scripts/build_debian_using_bzr.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env bash -# This script is for launchpad. -( -set -e -set -o xtrace -cd .. -cat > moose.recipe <<EOF -# bzr-builder format 0.3 deb-version {debupstream}+{revno} -lp:moose -EOF -# one can do nesting here. -if [ $# -gt 0 ]; then - if [[ "$1" == "update" ]]; then - echo "Fetching repo and creating tar-ball" - bzr dailydeb --allow-fallback-to-native moose.recipe .. - elif [[ "$1" == "pbuilder" ]]; then - bzr dailydeb --allow-fallback-to-native moose.recipe .. - sudo -E pbuilder build ../*.dsc - exit - fi -fi - -tarFile=`find .. -type f -maxdepth 1 -name "moose_3.0*.tar.gz"` -echo "Found tarfiles are $tarFile" -if [[ ! $tarFile ]]; then - echo "I could not file a tar.gz file. Can't continue" - echo "++ Cleaning previous mess" - rm -rf ../moose_3.0* ../moose-{* - echo "++ Let me download a fresh one" - bzr dailydeb --allow-fallback-to-native moose.recipe .. -fi - -rm -f moose.recipe -echo "Building debian package" -bzr builddeb -- -uc -us -) diff --git a/scripts/build_macosx_bundle.sh b/scripts/build_macosx_bundle.sh deleted file mode 100755 index cd5fbb61..00000000 --- a/scripts/build_macosx_bundle.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -mkdir -p _build -( - cd _build - rm -f moose*.dmg - rm -rf moose-3.0.1-Linux* - cmake -DCMAKE_INSTALL_PREFIX=/Moose.app .. - make -j4 - #cpack -G Bundle - cpack -G DragNDrop -V - 7z x moose-3.0.1-Linux-.dmg -) diff --git a/scripts/build_pypi.sh b/scripts/build_pypi.sh deleted file mode 100755 index 486bd242..00000000 --- a/scripts/build_pypi.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -set -e -# This creates a package for pip. For testing purpose -moose_dir=moose-3.0 -( - cd .. - svn export --force . scripts/$moose_dir -) -( - cp setup.py $moose_dir/ - cd $moose_dir - echo "Creating new archive" - if [ -f dist/$moose_dir.tar.gz ]; then - rm -f dist/*.tar.gz - fi - python setup.py sdist -vv - echo "Created new archive" - sudo pip install dist/*.tar.gz --no-clean - echo "Do the rest in $moose_dir" -) diff --git a/scripts/build_using_gcc_on_mac.sh b/scripts/build_using_gcc_on_mac.sh deleted file mode 100755 index d3b13406..00000000 --- a/scripts/build_using_gcc_on_mac.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -set -x -set -e -mkdir -p _build -( - cd _build - cmake -DCMAKE_C_COMPILER=gcc-mp-4.8 \ - -DCMAKE_CXX_COMPILER=g++-mp-4.8 .. \ - -DCMAKE_CXX_LINK_EXECUTABLE=/opt/local/bin/ld - make VERBOSE=1 -j4 -) diff --git a/scripts/cmake_sanity_check.py b/scripts/cmake_sanity_check.py deleted file mode 100755 index 075eb8b6..00000000 --- a/scripts/cmake_sanity_check.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -"""cmake_sanity_check.py: Check if Cmake files are ok. - -Last modified: Sat Jan 18, 2014 05:01PM - -NOTE: Run in this directory only. - -""" - -__author__ = "Dilawar Singh" -__copyright__ = "Copyright 2013, Dilawar Singh and NCBS Bangalore" -__credits__ = ["NCBS Bangalore"] -__license__ = "GNU GPL" -__version__ = "1.0.0" -__maintainer__ = "Dilawar Singh" -__email__ = "dilawars@ncbs.res.in" -__status__ = "Development" - -import sys -import os -import re -from collections import defaultdict - -makefiles = {} -cmakefiles = {} -makedirs = set() -cmakedirs = set() - -def check(d): - searchMakefiles(d) - checkMissingCMake() - checkSrcs() - -def checkMissingCMake(): - if (makedirs - cmakedirs): - print("[Failed] Test 1") - print("Following directories have Makefile but not a CMakeFiles.txt file.") - print("%s" % "\t\n".join(makedirs - cmakedirs)) - -def searchMakefiles(topdir): - for d, subd, fs in os.walk(topdir): - if "../_build" in d or ".." == d: continue - if "CMakeLists.txt" in fs: - cmakedirs.add(d) - cmakefiles[d] = fs - if "Makefile" in fs: - if "_build" in d: - continue - else: - makedirs.add(d) - makefiles[d] = fs - else: pass - -def checkSrcs(): - objPat = re.compile(r"\w+\.o") - srcPat = re.compile(r"\w+\.cpp") - srcs = [] - csrcs = [] - for d in makefiles: - with open(os.path.join(d, "Makefile"), "r") as f: - txt = f.read() - for i in txt.split("\n\n"): - if "OBJ =" in i.upper(): - for j in i.split(): - if ".o" in j.strip(): - srcs.append("%s"%(j.strip())) - try: - with open(os.path.join(d, "CMakeLists.txt"), "r") as f: - txt = f.read() - csrcs = srcPat.findall(txt) - except: - print("Dir {} does not have CMakeLists.txt".format(d)) - csrcs = [] - #print("[TEST 2] Checking if CMake is creating extra objects") - for csr in csrcs: - objName = csr.replace(".cpp", ".o") - if objName in srcs: - pass - else: - print(" Failed: In dir {}, CMake is creating extra object {}".format(d, objName)) - - pass - print("[TEST 3] Checking if CMake is missing some objects") - for obj in srcs: - srcName = obj.replace(".o", ".cpp") - if srcName in csrcs: pass - else: - print(" Failed: In dir {}, CMake is missing object {}".format(d, - srcName)) - -def main(): - test_dir = sys.argv[1] - check(test_dir) - - -if __name__ == '__main__': - main() diff --git a/scripts/color.sh b/scripts/color.sh deleted file mode 100755 index abac7110..00000000 --- a/scripts/color.sh +++ /dev/null @@ -1,48 +0,0 @@ -# Definitions of colors in bash -RESTORE='\033[0m' - -RED='\033[00;31m' -GREEN='\033[00;32m' -YELLOW='\033[00;33m' -BLUE='\033[00;34m' -PURPLE='\033[00;35m' -CYAN='\033[00;36m' -LIGHTGRAY='\033[00;37m' - -LRED='\033[01;31m' -LGREEN='\033[01;32m' -LYELLOW='\033[01;33m' -LBLUE='\033[01;34m' -LPURPLE='\033[01;35m' -LCYAN='\033[01;36m' -WHITE='\033[01;37m' - -function colorPrint -{ - case $1 in - "WARN") - echo -e "[WARN] ${LRED} $2 ${RESTORE} $3" - ;; - "INFO") - echo -e "[INFO] ${LGREEN} $2 ${RESTORE} $3" - ;; - "ERROR") - echo -e "[ERROR] ${RED} $2 ${RESTORE} $3" - ;; - "DEBUG") - echo -e "[DEBUG] ${YELLOW} $2 ${RESTORE} $3" - ;; - "STEP") - echo -e "[STEP] ${BLUE} $2 ${RESTORE} $3" - ;; - "TODO") - echo -e "[TODO] ${CYAN} $2 ${RESTORE} $3" - ;; - "||") - echo -e "|| ${PURPLE} $2 ${RESTORE} $3" - ;; - *) - echo -e "[$1] $2 $3" - ;; - esac -} diff --git a/scripts/moose b/scripts/moose deleted file mode 100755 index 97ae8a36..00000000 --- a/scripts/moose +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -moose.bin "$@" diff --git a/scripts/moose.desktop b/scripts/moose.desktop deleted file mode 100644 index 2b95bd6e..00000000 --- a/scripts/moose.desktop +++ /dev/null @@ -1,8 +0,0 @@ -[Desktop Entry] -Name=MOOSE -GenericName=MOOSE -Exec=moosegui -Type=Application -Version=3.0 -Icon=/usr/share/icons/moose/moose.png -Categories=Education;Science;Education;Chemistry; diff --git a/scripts/moosegui b/scripts/moosegui deleted file mode 100755 index 3acf2262..00000000 --- a/scripts/moosegui +++ /dev/null @@ -1,3 +0,0 @@ -#/bin/bash -# This script launches MOOSE gui. -cd /usr/lib/moose/gui && python mgui.py diff --git a/scripts/moosegui.py b/scripts/moosegui.py deleted file mode 100755 index 40feef0c..00000000 --- a/scripts/moosegui.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, Fifth -# Floor, Boston, MA 02110-1301, USA. - -import sys - -from mgui import mgui - -def main(): - mgui.main() - -if __name__ == '__main__': - main() - diff --git a/scripts/postinst b/scripts/postinst deleted file mode 100755 index 11fdb89b..00000000 --- a/scripts/postinst +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/sh -# postinst script for moose -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * <postinst> `configure' <most-recently-configured-version> -# * <old-postinst> `abort-upgrade' <new version> -# * <conflictor's-postinst> `abort-remove' `in-favour' <package> -# <new-version> -# * <postinst> `abort-remove' -# * <deconfigured's-postinst> `abort-deconfigure' `in-favour' -# <failed-install-package> <version> `removing' -# <conflicting-package> <version> -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - -case "$1" in - configure) - cd /usr/lib/moose/python && python setup.py install --record installed_files.txt - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - -#DEBHELPER# - -exit 0 diff --git a/scripts/prerm b/scripts/prerm deleted file mode 100755 index 3c976a65..00000000 --- a/scripts/prerm +++ /dev/null @@ -1,72 +0,0 @@ -#!/bin/sh -# prerm script for moose -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * <prerm> `remove' -# * <old-prerm> `upgrade' <new-version> -# * <new-prerm> `failed-upgrade' <old-version> -# * <conflictor's-prerm> `remove' `in-favour' <package> <new-version> -# * <deconfigured's-prerm> `deconfigure' `in-favour' -# <package-being-installed> <version> `removing' -# <conflicting-package> <version> -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - -case "$1" in - remove|upgrade|deconfigure) - if [ -d /usr/lib/moose/python ]; then - ( cd /usr/lib/moose/python && cat installed_files.txt | xargs rm -rf ) - fi - - if [ -d /usr/lib/moose ]; then - rm -R /usr/lib/moose - fi - - if [ -d /usr/share/doc/moose ]; then - rm -R /usr/share/doc/moose - fi - - if [ -d /usr/share/moose ]; then - rm -R /usr/share/moose - fi - - if [ -d /usr/share/pyshared/moose ]; then - rm -R /usr/share/pyshared/moose - fi - - pydistpkg_dir=`python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())"` - if [ -d $pydistpkg_dir/moose ]; - then - rm -R $pydistpkg_dir/moose - fi - if [ -f $HOME/Desktop/MooseGUI.desktop ]; - then - rm $HOME/Desktop/MooseGUI.desktop - fi - if [ -f $HOME/Desktop/HHSquidDemo.desktop ]; - then - rm $HOME/Desktop/HHSquidDemo.desktop - fi - - ;; - - failed-upgrade) - ;; - - *) - echo "prerm called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - -#DEBHELPER# - -exit 0 diff --git a/scripts/submit.py b/scripts/submit.py new file mode 100755 index 00000000..93118736 --- /dev/null +++ b/scripts/submit.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +from __future__ import division, print_function + +__author__ = "Dilawar Singh" +__copyright__ = "Copyright 2017-, Dilawar Singh" +__version__ = "1.0.0" +__maintainer__ = "Dilawar Singh" +__email__ = "dilawars@ncbs.res.in" +__status__ = "Development" + +import sys +import os +import socket +import time +import tarfile +import tempfile + +def gen_prefix( msg, maxlength = 10 ): + msg = '>%s' % msg + if len(msg) < maxlength: + msg += ' ' * (maxlength - len(msg)) + return msg[:maxlength].encode( 'utf-8' ) + +def write_data_to_socket(conn, msg): + msg = b'%010d%s' % (len(msg), msg) + conn.sendall(msg) + +def relativePath(path, base): + return os.path.relpath(path, base) + +def gen_payload( args ): + path = args.path + archive = os.path.join(tempfile.mkdtemp(), 'data.tar.bz2') + + # This mode (w|bz2) is suitable for streaming. The blocksize is default to + # 20*512 bytes. We change this to 2048 + with tarfile.open(archive, 'w|bz2', bufsize=2048 ) as h: + if len(args.main) > 0: + for i, f in enumerate(args.main): + h.add(f, arcname='__main__%d.py'%i) + if os.path.isfile(path): + h.add(path, os.path.basename(path)) + elif os.path.isdir(path): + for d, ds, fs in os.walk(path): + for f in fs: + p = os.path.join(d, f) + h.add(os.path.realpath(p), arcname=relativePath(p, path)) + else: + print( "[ERROR] Neither file nor directory %s" % path ) + + + with open(archive, 'rb') as f: + data = f.read() + return data + +def offload( args ): + zfile = create_zipfile( args.path ) + send_zip( zfile ) + +def loop( sock ): + sock.settimeout(1e-2) + while True: + try: + d = sock.recv(10).strip() + if len(d) > 0: + print(d) + except socket.timeout as e: + print( '.', end='' ) + sys.stdout.flush() + +def read_msg(conn): + d = conn.recv(1024) + try: + d = d.decode('utf8').strip() + except Exception as e: + pass + return d + +def save_bz2(conn, outfile): + # first 6 bytes always tell how much to read next. Make sure the submit job + # script has it + d = conn.recv(10) + while len(d) < 10: + try: + d = conn.recv(10) + except Exception as e: + print( "[ERROR] Error in format. First 6 bytes are size of msg." ) + continue + + print( "Needs to get %s bytes" % d ) + data = conn.recv(int(d)) + with open(outfile, 'wb') as f: + f.write(data) + return data + +def main( args ): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + host, port = args.server.split(':') + sock.connect( (host, int(port)) ) + sock.settimeout(1) + except Exception as e: + print( "[ERROR] Failed to connect to %s... " % args.server ) + print( e ) + quit() + + data = gen_payload( args ) + print( "[INFO ] Total bytes to send: %d" % len(data), end = '') + write_data_to_socket(sock, data) + print( ' ... [SENT]' ) + while True: + try: + d = read_msg( sock ) + print( d ) + if '>DONE SIMULATION' in d: + break + except socket.timeout as e: + time.sleep(0.5) + + data = save_bz2(sock, 'results.tar.bz2' ) + print( "[INFO ] All done" ) + + +if __name__ == '__main__': + import argparse + # Argument parser. + description = '''Submit a job to moose server.''' + parser = argparse.ArgumentParser(description=description) + parser.add_argument('path', metavar='path' + , help = 'File or directory to execute on server.' + ) + parser.add_argument('--main', '-m', action = 'append' + , required = False, default = [] + , help = 'In case of multiple files, scripts to execute' + ' on the server, e.g. -m file1.py -m file2.py.' + ' If not given, server will try to guess the best option.' + ) + parser.add_argument('--server', '-s' + , required = False, type=str, default='localhost:31417' + , help = 'IP address and PORT number of moose server e.g.' + ' 172.16.1.2:31416' + ) + class Args: pass + args = Args() + parser.parse_args(namespace=args) + main(args) diff --git a/shell/Shell.cpp b/shell/Shell.cpp index aa7cc983..1043f19d 100644 --- a/shell/Shell.cpp +++ b/shell/Shell.cpp @@ -9,6 +9,7 @@ #include <string> #include <algorithm> +#include <chrono> #include "../basecode/header.h" #include "../basecode/global.h" @@ -20,10 +21,12 @@ #include "../msg/OneToOneMsg.h" #include "../msg/OneToAllMsg.h" #include "../msg/SparseMsg.h" +#include "../builtins/SocketStreamer.h" #include "Shell.h" #include "Wildcard.h" + // Want to separate out this search path into the Makefile options #include "../scheduling/Clock.h" @@ -42,6 +45,7 @@ bool Shell::doReinit_( 0 ); bool Shell::isParserIdle_( 0 ); double Shell::runtime_( 0.0 ); + const Cinfo* Shell::initCinfo() { @@ -62,18 +66,19 @@ const Cinfo* Shell::initCinfo() //////////////////////////////////////////////////////////////// // Dest Finfos: Functions handled by Shell //////////////////////////////////////////////////////////////// - static DestFinfo handleUseClock( "useClock", - "Deals with assignment of path to a given clock." - " Arguments: path, field, tick number. ", - new EpFunc4< Shell, string, string, unsigned int, unsigned int >( - &Shell::handleUseClock ) + static DestFinfo handleUseClock( "useClock" + , "Deals with assignment of path to a given clock." + " Arguments: path, field, tick number. " + , new EpFunc4< Shell, string, string, unsigned int, unsigned int >(&Shell::handleUseClock ) ); - static DestFinfo handleCreate( "create", - "create( class, parent, newElm, name, numData, isGlobal )", - new EpFunc6< Shell, string, ObjId, Id, string, NodeBalance, unsigned int >( &Shell::handleCreate ) ); - static DestFinfo handleDelete( "delete", - "When applied to a regular object, this function operates " + static DestFinfo handleCreate( "create" + , "create( class, parent, newElm, name, numData, isGlobal )" + , new EpFunc6<Shell, string, ObjId, Id, string, NodeBalance, unsigned int>(&Shell::handleCreate) + ); + + static DestFinfo handleDelete( "delete" + , "When applied to a regular object, this function operates " "on the Id (element) specified by the ObjId argument. " "The function deletes the entire object " "array on this Id, including all dataEntries on it," @@ -81,41 +86,48 @@ const Cinfo* Shell::initCinfo() "is ignored, and all dataEntries are destroyed. \n" "When applied to a message: Destroys only that one specific " "message identified by the full ObjId. \n" - "Args: ObjId\n", - new EpFunc1< Shell, ObjId >( & Shell::destroy ) ); - - static DestFinfo handleAddMsg( "addMsg", - "Makes a msg. Arguments are:" - " msgtype, src object, src field, dest object, dest field", - new EpFunc6< Shell, string, ObjId, string, ObjId, string, unsigned int > - ( & Shell::handleAddMsg ) ); - static DestFinfo handleQuit( "quit", - "Stops simulation running and quits the simulator", - new OpFunc0< Shell >( & Shell::handleQuit ) ); - static DestFinfo handleMove( "move", - "handleMove( Id orig, Id newParent ): " - "moves an Element to a new parent", - new EpFunc2< Shell, Id, ObjId >( & Shell::handleMove ) ); - static DestFinfo handleCopy( "copy", - "handleCopy( vector< Id > args, string newName, unsigned int nCopies, bool toGlobal, bool copyExtMsgs ): " + "Args: ObjId\n" + , new EpFunc1< Shell, ObjId >( & Shell::destroy ) + ); + + static DestFinfo handleAddMsg( "addMsg" + , "Makes a msg. Arguments are:" + " msgtype, src object, src field, dest object, dest field" + , new EpFunc6< Shell, string, ObjId, string, ObjId, string, unsigned int >(&Shell::handleAddMsg) + ); + + static DestFinfo handleQuit( "quit" + , "Stops simulation running and quits the simulator" + , new OpFunc0< Shell >( & Shell::handleQuit ) + ); + static DestFinfo handleMove( "move" + , "handleMove( Id orig, Id newParent ): " + "moves an Element to a new parent" + , new EpFunc2<Shell, Id, ObjId>( & Shell::handleMove ) + ); + + static DestFinfo handleCopy( "copy" + , "handleCopy( vector< Id > args, string newName, unsigned int nCopies, bool toGlobal, bool copyExtMsgs ): " " The vector< Id > has Id orig, Id newParent, Id newElm. " "This function copies an Element and all its children to a new parent." " May also expand out the original into nCopies copies." " Normally all messages within the copy tree are also copied. " - " If the flag copyExtMsgs is true, then all msgs going out are also copied.", - new EpFunc5< Shell, vector< ObjId >, string, unsigned int, bool, bool >( - & Shell::handleCopy ) ); + " If the flag copyExtMsgs is true, then all msgs going out are also copied." + , new EpFunc5< Shell, vector< ObjId >, string, unsigned int, bool, bool >( + & Shell::handleCopy ) + ); - static DestFinfo setclock( "setclock", - "Assigns clock ticks. Args: tick#, dt", - new OpFunc2< Shell, unsigned int, double >( & Shell::doSetClock ) ); + static DestFinfo setclock( "setclock" + , "Assigns clock ticks. Args: tick#, dt" + , new OpFunc2< Shell, unsigned int, double >( & Shell::doSetClock ) + ); static Finfo* shellFinfos[] = { &setclock, -//////////////////////////////////////////////////////////////// -// Shared msg -//////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////// + // Shared msg + //////////////////////////////////////////////////////////////// // &master, // &worker, &handleCreate, @@ -220,7 +232,7 @@ Id Shell::doCreate( string type, ObjId parent, string name, { stringstream ss; ss << "Object with same path already present : " << parent.path() - << "/" << name; + << "/" << name; moose::showWarn( ss.str() ); return Id(); } @@ -358,17 +370,14 @@ bool isDoingReinit() { static Id clockId( 1 ); assert( clockId.element() != 0 ); - - return ( reinterpret_cast< const Clock* >( - clockId.eref().data() ) )->isDoingReinit(); + return (reinterpret_cast<const Clock*>(clockId.eref().data()))->isDoingReinit(); } + void Shell::doReinit( ) { - Id clockId( 1 ); SetGet0::set( clockId, "reinit" ); - } void Shell::doStop( ) @@ -1028,7 +1037,7 @@ void Shell::cleanSimulation() if ( i->value() > 4 ) /* These are created by users */ { LOG( moose::debug - , "Shell::cleanSimulation: deleted cruft at " << + , "Shell::cleanSimulation: deleted cruft at " << i->value() << ": " << i->path()); s->doDelete( *i ); } diff --git a/shell/Shell.h b/shell/Shell.h index 40c36b3c..1853a1ee 100644 --- a/shell/Shell.h +++ b/shell/Shell.h @@ -44,41 +44,6 @@ public: Shell(); ~Shell(); -#ifdef CYMOOSE - - /** - * @brief Initialize shell. - * - * @return Pointer to shell. - * - * This function initialize shell and returns a pointer to it. - * This function must create a fully functional shell which can - * be used by cython interface. - */ - Shell* initShell(); - - - /** - * @brief A thin wrapper around doCreate function. Used in - * cython interface. - * - * @param type Type of Moose-element to be created e.g. Table, - * Compartment, etc. - * @param parent Parent element under which this element is - * being created. - * @param name Name of the element. String. - * @param numData - * @param nodePolicy - * @param preferredNode - * - * @return Id of the element. - */ - Id create( string type, string name, unsigned int numData, - NodePolicy nodePolicy = MooseBlockBalance, - unsigned int preferredNode = 1 ); - - -#endif /* ----- CYMOOSE ----- */ /////////////////////////////////////////////////////////// // Field functions /////////////////////////////////////////////////////////// @@ -102,6 +67,8 @@ public: */ bool isRunning() const; + void setupSocketStreamer(const string host, const int port ); + /////////////////////////////////////////////////////////// // Parser functions /////////////////////////////////////////////////////////// diff --git a/shell/Wildcard.cpp b/shell/Wildcard.cpp index 9031759a..abfb4f7d 100644 --- a/shell/Wildcard.cpp +++ b/shell/Wildcard.cpp @@ -151,9 +151,10 @@ static void myUnique(vector<ObjId>& ret) ret.resize(j); } -int wildcardFind(const string& path, vector<ObjId>& ret) +int wildcardFind(const string& path, vector<ObjId>& ret, bool clear) { - ret.resize( 0 ); + if(clear) + ret.resize( 0 ); simpleWildcardFind( path, ret ); myUnique( ret ); return ret.size(); diff --git a/shell/Wildcard.h b/shell/Wildcard.h index 912b3708..1fd97578 100644 --- a/shell/Wildcard.h +++ b/shell/Wildcard.h @@ -57,8 +57,10 @@ int simpleWildcardFind( const string& path, vector<ObjId>& ret); * wildcardFind returns the number of Ids found. * This behaves the same as simpleWildcardFind, except that it eliminates * non-unique entries, and in the process will scramble the ordering. + * + * If clear=true, then reset the ret to 0 size. */ -int wildcardFind(const string& n, vector<ObjId>& ret); +int wildcardFind(const string& n, vector<ObjId>& ret, bool clear = true); /** * Recursive function to compare all descendants and cram matches into ret. diff --git a/tests/python/models.py b/tests/python/models.py new file mode 100644 index 00000000..3a5443f5 --- /dev/null +++ b/tests/python/models.py @@ -0,0 +1,26 @@ +# Library of simple models. +import moose + +def simple_model_a(): + compt = moose.CubeMesh( '/compt' ) + r = moose.Reac( '/compt/r' ) + a = moose.Pool( '/compt/a' ) + a.concInit = 1 + b = moose.Pool( '/compt/b' ) + b.concInit = 2 + c = moose.Pool( '/compt/c' ) + c.concInit = 0.5 + moose.connect( r, 'sub', a, 'reac' ) + moose.connect( r, 'prd', b, 'reac' ) + moose.connect( r, 'prd', c, 'reac' ) + r.Kf = 0.1 + r.Kb = 0.01 + + tabA = moose.Table2( '/compt/a/tab' ) + tabB = moose.Table2( '/compt/tabB' ) + tabC = moose.Table2( '/compt/tabB/tabC' ) + print(tabA, tabB, tabC) + moose.connect( tabA, 'requestOut', a, 'getConc' ) + moose.connect( tabB, 'requestOut', b, 'getConc' ) + moose.connect( tabC, 'requestOut', c, 'getConc' ) + return [tabA, tabB, tabC] diff --git a/tests/python/test_moose_attribs.py b/tests/python/test_moose_attribs.py index 4d3d9770..b10a2b30 100644 --- a/tests/python/test_moose_attribs.py +++ b/tests/python/test_moose_attribs.py @@ -44,7 +44,7 @@ attribs = ['AdExIF', 'AdThreshIF', 'Adaptor', 'Annotator', 'Arith', 'BufPool', 'element', 'exists', 'finfotypes', 'fixXreacs', 'genesis', 'getCwe', 'getField', 'getFieldDict', 'getFieldNames', 'getfielddoc', 'getmoosedoc', 'isRunning', - 'known_types', 'le', 'listmsg', 'loadModel', 'melement', + 'known_types', 'le', 'listmsg', 'loadModelInternal', 'melement', 'mergeChemModel', 'moose', 'mooseAddChemSolver', 'mooseDeleteChemSolver', 'mooseReadNML2', 'mooseReadSBML', 'mooseWriteKkit', 'mooseWriteNML2', 'mooseWriteSBML', @@ -52,7 +52,7 @@ attribs = ['AdExIF', 'AdThreshIF', 'Adaptor', 'Annotator', 'Arith', 'BufPool', 'nml2Import_', 'pager', 'print_utils', 'pwe', 'pydoc', 'rand', 'reinit', 'seed', 'sequence_types', 'setClock', 'setCwe', 'showfield', - 'showfields', 'showmsg', 'splitext', 'start', 'stop', 'syncDataHandler', + 'showfields', 'showmsg', 'start', 'stop', 'syncDataHandler', 'test', 'testSched', 'toUnicode', 'useClock', 'utils', 'vec', 'version', 'warnings', 'wildcardFind'] diff --git a/tests/python/test_socket_streamer_tcp.py b/tests/python/test_socket_streamer_tcp.py new file mode 100644 index 00000000..497b66fb --- /dev/null +++ b/tests/python/test_socket_streamer_tcp.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- +"""test_socket_streamer.py: + + MOOSE must create a socket server on PORT 31616 (default) + or setup moose.SocketStreamer port to appropriate port number. + + Client can read data from this socket. +""" + +from __future__ import print_function + +__author__ = "Dilawar Singh" +__copyright__ = "Copyright 2016, Dilawar Singh" +__credits__ = ["NCBS Bangalore"] +__license__ = "GNU GPL" +__version__ = "1.0.0" +__maintainer__ = "Dilawar Singh" +__email__ = "dilawars@ncbs.res.in" +__status__ = "Development" + +import os +import sys +sys.path.append( os.path.dirname(__file__)) +import time +import socket +import numpy as np +import threading +import moose +import models +import json +from collections import defaultdict + +finish_all_ = False + +print( '[INFO] Using moose form %s' % moose.__file__ ) + +def get_msg(s, n=1024): + d = s.recv( n, socket.MSG_WAITALL) + while len(d) < n: + d += s.recv(n-len(d), socket.MSG_WAITALL) + return d + +def socket_client(host='127.0.0.1', port = 31416): + # This function waits for socket to be available. + global finish_all_ + s = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) + while 1: + if finish_all_: + print( '[INFO] MOOSE is done before I could connect' ) + break + # print('Py: Trying to connect to %s, %s' % (host, port)) + # print( end = '.' ) + try: + s.connect( ('', port) ) + break + except Exception as e: + continue + print(e, end = 'x') + sys.stdout.flush() + pass + + print( 'Connected' ) + if not finish_all_: + print( 'Py: Connected with socket.' ) + + # This is client reponsibility to read the data. + s.settimeout(0.1) + data = b'' + while not finish_all_: + try: + data += get_msg(s) + except socket.timeout as e: + print( e, end = ' ' ) + + s.close() + assert data, "No data streamed" + print( 'recieved data:\n', data ) + res = defaultdict(list) + for x in data.split(b'\n'): + if not x.strip(): + continue + d = json.loads(x) + for k, v in d.items(): + res[k] += v + + expected = {u'/compt/tabB/tabC': ([25.,1.07754388], [14.71960144, 0.16830373]) + , u'/compt/a/tab': ([25., 0.42467006], [14.71960144, 0.16766705]) + , u'/compt/tabB': ([25., 2.57797725], [14.71960144, 0.16842971]) + } + nd = {} + for k in res: + v = res[k] + nd[k] = (np.mean(v, axis=0), np.std(v, axis=0)) + assert np.isclose(expected[k], nd[k]).all(), \ + "Exptected %s, got %s" % (str(expected[k]), str(nd[k])) + +def sanity_test( ): + a = moose.Table( '/t1' ) + b = moose.Table( '/t1/t1' ) + c = moose.Table( '/t1/t1/t1' ) + st = moose.SocketStreamer( '/s' ) + st.addTable( a ) + assert( st.numTables == 1 ) + st.addTable( b ) + assert( st.numTables == 2 ) + st.addTable( c ) + assert( st.numTables == 3 ) + st.addTable( c ) + assert( st.numTables == 3 ) + st.addTable( c ) + assert( st.numTables == 3 ) + + st.removeTable( c ) + assert( st.numTables == 2 ) + st.removeTable( c ) + assert( st.numTables == 2 ) + st.removeTable( a ) + assert( st.numTables == 1 ) + st.removeTable( b ) + assert( st.numTables == 0 ) + st.removeTable( b ) + assert( st.numTables == 0 ) + print( 'Sanity test passed' ) + + st.addTables( [a, b, c ]) + assert st.numTables == 3 + st.removeTables( [a, a, c] ) + assert st.numTables == 1 + moose.delete( '/t1' ) + moose.delete( '/s' ) + +def test(): + global finish_all_ + os.environ['MOOSE_STREAMER_ADDRESS'] = 'http://127.0.0.1:31416' + client = threading.Thread(target=socket_client, args=()) + # client.daemon = True + client.start() + print( '[INFO] Socket client is running now' ) + tables = models.simple_model_a() + time.sleep(0.1) + moose.reinit() + moose.start(50) + print( 'MOOSE is done' ) + + # sleep for some time so data can be read. + time.sleep(1) + finish_all_ = True + client.join() + print( 'Test 1 passed' ) + +def test_without_env(): + global finish_all_ + os.environ['MOOSE_STREAMER_ADDRESS'] = '' + client = threading.Thread(target=socket_client, args=()) + #client.daemon = True + client.start() + print( '[INFO] Socket client is running now' ) + tables = create_model() + # Now create a streamer and use it to write to a stream + st = moose.SocketStreamer( '/compt/streamer' ) + st.address = 'http://127.0.0.1:31416' + assert st.port == 31416, "Got %s expected %s" % (st.port, expected) + st.addTable(tables[0]) + st.addTables(tables[1:]) + assert st.numTables == 3 + # Give some time for socket client to make connection. + moose.reinit() + moose.start(50) + time.sleep(1) + print( 'MOOSE is done' ) + # sleep for some time so data can be read. + finish_all_ = True + client.join() + print( 'Test 2 passed' ) + +def main( ): + test( ) + # test_without_env() + print( '[INFO] All tests passed' ) + +if __name__ == '__main__': + main() diff --git a/tests/python/test_socket_streamer_uds.py b/tests/python/test_socket_streamer_uds.py new file mode 100644 index 00000000..542c3a46 --- /dev/null +++ b/tests/python/test_socket_streamer_uds.py @@ -0,0 +1,128 @@ +# -*- coding: utf-8 -*- +"""test_socket_streamer.py: + + MOOSE must create a socket server on PORT 31616 (default) + or setup moose.SocketStreamer port to appropriate port number. + + Client can read data from this socket. +""" + +from __future__ import print_function + +__author__ = "Dilawar Singh" +__copyright__ = "Copyright 2016, Dilawar Singh" +__credits__ = ["NCBS Bangalore"] +__license__ = "GNU GPL" +__version__ = "1.0.0" +__maintainer__ = "Dilawar Singh" +__email__ = "dilawars@ncbs.res.in" +__status__ = "Development" + +import os +import sys +sys.path.append(os.path.dirname(__file__)) +import time +import socket +import numpy as np +import threading +import moose +import json +import models +from collections import defaultdict + +finish_all_ = False + +print( '[INFO] Using moose form %s' % moose.__file__ ) + +sockFile_ = '/tmp/MOOSE' + +def get_msg(s, n=1024): + d = s.recv(n) + while(len(d) < n): + d1 = s.recv(n-len(d)) + d += d1 + return d + +def socket_client( ): + # This function waits for socket to be available. + global finish_all_ + global sockFile_ + s = socket.socket( socket.AF_UNIX, socket.SOCK_STREAM ) + address = sockFile_ + while 1: + if finish_all_: + print( '[INFO] MOOSE is done before I could connect' ) + break + # print('Py: Trying to connect to %s, %s' % (host, port)) + # print( end = '.' ) + try: + s.connect( address ) + break + except Exception as e: + pass + + if not finish_all_: + print( 'Py: Connected with socket.' ) + + # This is client reponsibility to read the data. + data = b'' + s.settimeout(1) + while not finish_all_: + try: + d = get_msg(s, 1024) + data += d + except socket.timeout as e: + pass + s.close() + + assert data, "No data streamed" + res = defaultdict(list) + for x in data.split(b'\n'): + if not x.strip(): + continue + x = x.decode( 'utf8' ) + try: + d = json.loads(x) + except Exception as e: + print( data ) + raise e + for k, v in d.items(): + res[k] += v + + expected = {u'/compt/tabB/tabC': ([25.,1.07754388], [14.71960144, 0.16830373]) + , u'/compt/a/tab': ([25., 0.42467006], [14.71960144, 0.16766705]) + , u'/compt/tabB': ([25., 2.57797725], [14.71960144, 0.16842971]) + } + nd = {} + for k in res: + v = res[k] + nd[k] = (np.mean(v, axis=0), np.std(v, axis=0)) + assert np.isclose(expected[k], nd[k]).all(), \ + "Exptected %s, got %s" % (str(expected[k]), str(nd[k])) + +def test(): + global finish_all_ + client = threading.Thread(target=socket_client, args=()) + #client.daemon = True + client.start() + print( '[INFO] Socket client is running now' ) + tables = models.simple_model_a() + # Now create a streamer and use it to write to a stream + os.environ['MOOSE_STREAMER_ADDRESS'] = 'file:///tmp/moose' + + # Give some time for socket client to make connection. + moose.reinit() + moose.start(50) + time.sleep(0.1) + finish_all_ = True + print( 'MOOSE is done' ) + # sleep for some time so data can be read. + client.join() + print( 'Test 2 passed' ) + +def main( ): + test() + print( '[INFO] All tests passed' ) + +if __name__ == '__main__': + main() diff --git a/utility/setupenv.cpp b/utility/setupenv.cpp index 3d8b3271..422d3471 100644 --- a/utility/setupenv.cpp +++ b/utility/setupenv.cpp @@ -38,6 +38,7 @@ using namespace std; extern unsigned getNumCores(); namespace moose { + const map<string, string>& getArgMap() { static map<string, string> argmap; @@ -105,6 +106,23 @@ namespace moose { return argmap; } + /* --------------------------------------------------------------------------*/ + /** + * @Synopsis Get environment valus. + * + * @Param env Name of the environment variable. + * + * @Returns value of environment if set, empty string otherwise. + */ + /* ----------------------------------------------------------------------------*/ + string getEnv( const string& env ) + { + const char* pEnv = std::getenv( env.c_str() ); + if( pEnv ) + return string(pEnv); + return ""; + } + } diff --git a/utility/strutil.cpp b/utility/strutil.cpp index da5ee41f..95b09450 100644 --- a/utility/strutil.cpp +++ b/utility/strutil.cpp @@ -5,7 +5,9 @@ * E-mail: ray.subhasis@gmail.com * Created: 2007-09-25 12:12:10 ********************************************************************/ + #include <string> +#include <sstream> #include <iostream> #include <vector> #include "strutil.h" diff --git a/utility/strutil.h b/utility/strutil.h index a5b1760b..4d95c141 100644 --- a/utility/strutil.h +++ b/utility/strutil.h @@ -48,10 +48,33 @@ namespace moose */ int strncasecmp( const std::string& a, const std::string& b, size_t n); - /** - * Generate random string of given length. - */ - std::string random_string( const unsigned size ); + /** + * Generate random string of given length. + */ + std::string random_string( const unsigned size ); + + + /* --------------------------------------------------------------------------*/ + /** + * @Synopsis Converts a vector to string. + * + * @Param vec + * + * @Returns + */ + /* ----------------------------------------------------------------------------*/ + template<typename T=double> + std::string vectorToCSV( const std::vector<T>& vec) + { + std::stringstream ss; + for(size_t i = 0; i < vec.size(); i++) + ss << vec[i] << ','; + auto res = ss.str(); + if( ',' == res.back()) + res.pop_back(); + return res; + } + } #endif //_STRINGUTIL_H diff --git a/utility/utility.h b/utility/utility.h index 4d551018..ee0e88d7 100644 --- a/utility/utility.h +++ b/utility/utility.h @@ -20,7 +20,10 @@ namespace moose char shortType(std::string type); char innerType(char typecode); char shortFinfo(std::string ftype); + + // In setuptevn.cpp const map<std::string, std::string>& getArgMap(); + string getEnv( const string& env); /** * @brief Givem path of MOOSE element, return its name. It's behaviour is -- GitLab