diff --git a/moose-core/.travis.yml b/moose-core/.travis.yml index e69122259038e110c41ef471f75be1f04effb3c0..c4aa5e91786a7e86eee00c2f24b8972b7a4bc1be 100644 --- a/moose-core/.travis.yml +++ b/moose-core/.travis.yml @@ -7,7 +7,10 @@ os: - linux - osx -osx_image: xcode10 +matrix: + include: + - os : osx + osx_image: xcode10 notifications: email: diff --git a/moose-core/.travis/travis_prepare_osx.sh b/moose-core/.travis/travis_prepare_osx.sh index d8aa29a1719ebd80e12a0e5b2b6920313cf1cceb..d56638ed70f802230d570697cc3d3dc3fdac8bdd 100755 --- a/moose-core/.travis/travis_prepare_osx.sh +++ b/moose-core/.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/moose-core/CMakeLists.txt b/moose-core/CMakeLists.txt index ec094e5877f7b3709101ccf45242d0240fff65d9..b30ca55de3a35154d864570dbc974bf413b51c1b 100644 --- a/moose-core/CMakeLists.txt +++ b/moose-core/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/moose-core/INSTALL.md b/moose-core/INSTALL.md index 6f2272b2c130c9e9b02516dffe83cb31a6cd17fc..63af4f3a9ce0ff4619203d14cf1a768e764ae875 100644 --- a/moose-core/INSTALL.md +++ b/moose-core/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/moose-core/basecode/ObjId.cpp b/moose-core/basecode/ObjId.cpp index 9e846603ff806d71c520b3b1c79e2464533659ca..9c1c823139e778920457ddc6093d4b3d027aee6a 100644 --- a/moose-core/basecode/ObjId.cpp +++ b/moose-core/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/moose-core/basecode/ObjId.h b/moose-core/basecode/ObjId.h index 9f279f453fe2619698501642075dae85aa90a938..ab91204c2360c356f657d3fc99388d721a65b159 100644 --- a/moose-core/basecode/ObjId.h +++ b/moose-core/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/moose-core/basecode/SetGet.h b/moose-core/basecode/SetGet.h index fc855b2071b4c123c631be6fcc9786e051b6b5dd..1788d6addae20084dac985df22bf999304fd506c 100644 --- a/moose-core/basecode/SetGet.h +++ b/moose-core/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/moose-core/biophysics/CaConcBase.cpp b/moose-core/biophysics/CaConcBase.cpp index c95c386a86bc6f8687d3537391b405a9abd94da3..1f974bb30579fdc701a89dd92e702905a4520b05 100644 --- a/moose-core/biophysics/CaConcBase.cpp +++ b/moose-core/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/moose-core/biophysics/HHGate.cpp b/moose-core/biophysics/HHGate.cpp index 0e8ca5841a37cf2603dc1c20c4c02cc31478c06b..eadfeca86fbdfa864bc7496e58eec66523600c00 100644 --- a/moose-core/biophysics/HHGate.cpp +++ b/moose-core/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/moose-core/biophysics/HHGate.h b/moose-core/biophysics/HHGate.h index a5c79eb5dfcc68e65ef591c80df5b6fd91d97995..eadb2821cf1e3f293296723d4d7cec768dd76e54 100644 --- a/moose-core/biophysics/HHGate.h +++ b/moose-core/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/moose-core/biophysics/Neuron.cpp b/moose-core/biophysics/Neuron.cpp index 15ec8e60ec4b4ffcc82a852f3b3c5985ecc8d518..4d5993f1676aa1a4fe03ba6719563880115e8ee6 100644 --- a/moose-core/biophysics/Neuron.cpp +++ b/moose-core/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/moose-core/builtins/CMakeLists.txt b/moose-core/builtins/CMakeLists.txt index 9c2260113e0160cec1e5f827f1d36f2bf3c3a17c..3df4cd964824591929dcd158f7c87b01564dd66e 100644 --- a/moose-core/builtins/CMakeLists.txt +++ b/moose-core/builtins/CMakeLists.txt @@ -19,6 +19,7 @@ set(SRCS Stats.cpp Interpol2D.cpp SpikeStats.cpp + SocketStreamer.cpp testBuiltins.cpp ) diff --git a/moose-core/builtins/SocketStreamer.cpp b/moose-core/builtins/SocketStreamer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e3097f088bd2b7f99d52743a52ce249ff7d01141 --- /dev/null +++ b/moose-core/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/moose-core/builtins/SocketStreamer.h b/moose-core/builtins/SocketStreamer.h new file mode 100644 index 0000000000000000000000000000000000000000..c52bb7dd4d1419895d16d7ba3f9ddc9cb331fa45 --- /dev/null +++ b/moose-core/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/moose-core/builtins/Streamer.cpp b/moose-core/builtins/Streamer.cpp index 5ecde62108ae1d59ee861868eedd83818ae4275e..c583be1fee2ee8cc00ec68c1f6ee8e4cef2a4293 100644 --- a/moose-core/builtins/Streamer.cpp +++ b/moose-core/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/moose-core/builtins/StreamerBase.cpp b/moose-core/builtins/StreamerBase.cpp index cb436b99a6926110b2f5a6073a801de40e5e705c..e6d590be0fe1b2a06a2c242946e4814a32a8ec38 100644 --- a/moose-core/builtins/StreamerBase.cpp +++ b/moose-core/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/moose-core/builtins/StreamerBase.h b/moose-core/builtins/StreamerBase.h index c23dd5001c59b9a13b6f8852a5a14330386ac4df..b3e035b1ae2b87663d64cbba9196e5c3be997ed9 100644 --- a/moose-core/builtins/StreamerBase.h +++ b/moose-core/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/moose-core/builtins/Table.cpp b/moose-core/builtins/Table.cpp index f5a6b7710e336958109d44dfb1e51d7e4ff724fd..4f426b148e09428928a75bb2569bf04c0c2263cd 100644 --- a/moose-core/builtins/Table.cpp +++ b/moose-core/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/moose-core/builtins/Table.h b/moose-core/builtins/Table.h index 34397cde40e0056b5a57517d54831db73cbc9b52..b3a0293bf7796fec8e568063f1e6e2f1e59a09c2 100644 --- a/moose-core/builtins/Table.h +++ b/moose-core/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/moose-core/builtins/TableBase.cpp b/moose-core/builtins/TableBase.cpp index e4467c6f0be8b4f70e169ce2457fa05d14b04e9a..c0976bc2de0d12032059c34bbdf2ab7c5bed270a 100644 --- a/moose-core/builtins/TableBase.cpp +++ b/moose-core/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/moose-core/builtins/TableBase.h b/moose-core/builtins/TableBase.h index ada46bec7d4a544fd8dde22fbf84891dd101fb2e..d04389711a9c1445436643069541e08ac2eacf76 100644 --- a/moose-core/builtins/TableBase.h +++ b/moose-core/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/moose-core/hsolve/HSolveActive.cpp b/moose-core/hsolve/HSolveActive.cpp index 662c4cc80f5b9eac11258b2c8257568f0928810d..ecb48c4baac39b1c5322a74080d0af635cbbefd6 100644 --- a/moose-core/hsolve/HSolveActive.cpp +++ b/moose-core/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/moose-core/hsolve/HSolveActive.h b/moose-core/hsolve/HSolveActive.h index affc85256102626d53b4a5da1bfb7baad578c8df..ad2fd46dce1a2395c8913e0a27c2a0825af2565f 100644 --- a/moose-core/hsolve/HSolveActive.h +++ b/moose-core/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/moose-core/hsolve/HSolveActiveSetup.cpp b/moose-core/hsolve/HSolveActiveSetup.cpp index 55edc3be10e53dc538cf91cb4951365d00c7b62c..5ba896116596239e664cf50cafa25816dc64884f 100644 --- a/moose-core/hsolve/HSolveActiveSetup.cpp +++ b/moose-core/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/moose-core/hsolve/HSolveInterface.cpp b/moose-core/hsolve/HSolveInterface.cpp index 548646dd96a1af2b32c07d4390b39cbe795e887c..455c8cb7b9157d06f87821deda1a53f70c5020b6 100644 --- a/moose-core/hsolve/HSolveInterface.cpp +++ b/moose-core/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/moose-core/ksolve/testKsolve.cpp b/moose-core/ksolve/testKsolve.cpp index 64ae8db71ebe0f9846643d25352757901dcaacc4..12c0eb88aa3fff185a58295b2aa46f94d0c8d7bb 100644 --- a/moose-core/ksolve/testKsolve.cpp +++ b/moose-core/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/moose-core/pymoose/moosemodule.cpp b/moose-core/pymoose/moosemodule.cpp index 5e811d0283737874a826f7698da7f5129d3aa4ab..0a71f46667693213040b1a899ecde7db60b771ea 100644 --- a/moose-core/pymoose/moosemodule.cpp +++ b/moose-core/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/moose-core/pymoose/moosemodule.h b/moose-core/pymoose/moosemodule.h index 7ef0e79375c65c8fddf49c9e4fdaec1c4807ebc1..470b17f100a17c86c51ae9ec0e5fbd4e80ea54bf 100644 --- a/moose-core/pymoose/moosemodule.h +++ b/moose-core/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/moose-core/python/moose/SBML/readSBML.py b/moose-core/python/moose/SBML/readSBML.py index f8e74f7e13bdd9194b60dadc4f1f17a336fdd153..356d2400314d2b4623594f8057943bdfc93031ef 100644 --- a/moose-core/python/moose/SBML/readSBML.py +++ b/moose-core/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/moose-core/python/moose/SBML/writeSBML.py b/moose-core/python/moose/SBML/writeSBML.py index a3d898d44c2b0c02d2f8e4f55404332f6ac9c86a..d8325ee2a978cb49af6992f48ded5daa347da607 100644 --- a/moose-core/python/moose/SBML/writeSBML.py +++ b/moose-core/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/moose-core/python/moose/__init__.py b/moose-core/python/moose/__init__.py index 407b6950d8246916d0178f6962a7f28bcae4c51c..3c398033985d709c65bdccbbddbcde446198aa24 100644 --- a/moose-core/python/moose/__init__.py +++ b/moose-core/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/moose-core/python/moose/chemMerge/merge.py b/moose-core/python/moose/chemMerge/merge.py index 6b37ae44d5665752dc1776de9cfeb3e560984717..d3724c8cff0a22ba04d6bcfe1e507730f81f0ccc 100644 --- a/moose-core/python/moose/chemMerge/merge.py +++ b/moose-core/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/moose-core/python/moose/chemUtil/chemConnectUtil.py b/moose-core/python/moose/chemUtil/chemConnectUtil.py index bbb18ed55eee94434adf5dde60d64db7ccdb5086..9c92e613786c8448f0075ac67bf46cc92e14c05e 100644 --- a/moose-core/python/moose/chemUtil/chemConnectUtil.py +++ b/moose-core/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/moose-core/python/moose/genesis/writeKkit.py b/moose-core/python/moose/genesis/writeKkit.py index 4dc03c076b34ef859a9df055c440283c945aedc6..6227bc0b638f7ec00e61250c5d8169c1a6dcabcf 100644 --- a/moose-core/python/moose/genesis/writeKkit.py +++ b/moose-core/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/moose-core/python/moose/moose.py b/moose-core/python/moose/moose.py index a55bc7be1f1c6b86d36b838d68a7be7b9e245d17..c3c6b60db6cf3de1c49cd6d2e5516d7bc2b91d22 100644 --- a/moose-core/python/moose/moose.py +++ b/moose-core/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/moose-core/python/moose/neuroml2/reader.py b/moose-core/python/moose/neuroml2/reader.py index 2f2e2d85c8c35c5b227b5e436fd4c39c26521409..1629e6de7a3eaa73d574a42ea0a6a4f81103b631 100644 --- a/moose-core/python/moose/neuroml2/reader.py +++ b/moose-core/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/moose-core/python/moose/neuroml2/units.py b/moose-core/python/moose/neuroml2/units.py index 795129a51377b232354eb480ebe0ab898074483c..b85bf6f7912070f3c60c5eed8d28f6bef289e72e 100644 --- a/moose-core/python/moose/neuroml2/units.py +++ b/moose-core/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/moose-core/python/moose/server.py b/moose-core/python/moose/server.py new file mode 100644 index 0000000000000000000000000000000000000000..400058a39e6b21c2d4cbee6de296046d4d940abd --- /dev/null +++ b/moose-core/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/moose-core/python/rdesigneur/rdesigneur.py b/moose-core/python/rdesigneur/rdesigneur.py index 6ad93d02b89981d95b1bc215df7d6e8ecffce079..c1cb25ec96a07353787257765479a6bfa90d1966 100644 --- a/moose-core/python/rdesigneur/rdesigneur.py +++ b/moose-core/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/moose-core/python/rdesigneur/rdesigneurProtos.py b/moose-core/python/rdesigneur/rdesigneurProtos.py index cade79201b388014a2719c513526a0c0eda63417..991bf4e8f313938571fa0dcf311c87f61aecda4b 100644 --- a/moose-core/python/rdesigneur/rdesigneurProtos.py +++ b/moose-core/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/moose-core/scheduling/Clock.cpp b/moose-core/scheduling/Clock.cpp index aad5c0666fa608e09e53c7ce1de7e4b69a297354..dd60aecf359bf4fc8698a40031a1f0fb2f6fc4a8 100644 --- a/moose-core/scheduling/Clock.cpp +++ b/moose-core/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/moose-core/scripts/Makefile.wheel b/moose-core/scripts/Makefile.wheel deleted file mode 100644 index 86f502625bb50ba083a52562f3e39395e2d9fc83..0000000000000000000000000000000000000000 --- a/moose-core/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/moose-core/scripts/Portfile b/moose-core/scripts/Portfile deleted file mode 100644 index ee48c5682dea494e165937a62404947029f42a5c..0000000000000000000000000000000000000000 --- a/moose-core/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/moose-core/scripts/build-moose-core b/moose-core/scripts/build-moose-core deleted file mode 100755 index 61d0abacb1feff866cd2bbd50bd0691cf732fba3..0000000000000000000000000000000000000000 --- a/moose-core/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/moose-core/scripts/build_debian.sh b/moose-core/scripts/build_debian.sh deleted file mode 100755 index f0f9247ee5b9c87b133c7cfda5476024da390872..0000000000000000000000000000000000000000 --- a/moose-core/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/moose-core/scripts/build_debian_locally_on_ubuntu.sh b/moose-core/scripts/build_debian_locally_on_ubuntu.sh deleted file mode 100755 index a7ba62b2e557d76e094edb78bc73c1ab3bb3ea18..0000000000000000000000000000000000000000 --- a/moose-core/scripts/build_debian_locally_on_ubuntu.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash -( - cd .. - debuild -uc -us -) diff --git a/moose-core/scripts/build_debian_using_bzr.sh b/moose-core/scripts/build_debian_using_bzr.sh deleted file mode 100755 index f0f9247ee5b9c87b133c7cfda5476024da390872..0000000000000000000000000000000000000000 --- a/moose-core/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/moose-core/scripts/build_macosx_bundle.sh b/moose-core/scripts/build_macosx_bundle.sh deleted file mode 100755 index cd5fbb6175aad1df30e818e1d61b5c6ba3dbbedf..0000000000000000000000000000000000000000 --- a/moose-core/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/moose-core/scripts/build_pypi.sh b/moose-core/scripts/build_pypi.sh deleted file mode 100755 index 486bd2421174415fa08c46c5d920a03309a02e58..0000000000000000000000000000000000000000 --- a/moose-core/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/moose-core/scripts/build_using_gcc_on_mac.sh b/moose-core/scripts/build_using_gcc_on_mac.sh deleted file mode 100755 index d3b13406f710065085156118dd48fc78a7fa7d43..0000000000000000000000000000000000000000 --- a/moose-core/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/moose-core/scripts/cmake_sanity_check.py b/moose-core/scripts/cmake_sanity_check.py deleted file mode 100755 index 075eb8b6b4a8aa2fe55771cafd5c181e162b0671..0000000000000000000000000000000000000000 --- a/moose-core/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/moose-core/scripts/color.sh b/moose-core/scripts/color.sh deleted file mode 100755 index abac71107e7bc7f3793af150c98c8bdb93154fce..0000000000000000000000000000000000000000 --- a/moose-core/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/moose-core/scripts/moose b/moose-core/scripts/moose deleted file mode 100755 index 97ae8a36b4402246c529d0b770367165ca4c6d78..0000000000000000000000000000000000000000 --- a/moose-core/scripts/moose +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -moose.bin "$@" diff --git a/moose-core/scripts/moose.desktop b/moose-core/scripts/moose.desktop deleted file mode 100644 index 2b95bd6e0ab88f2a18df6f2f1bae6a3e3f7f22a7..0000000000000000000000000000000000000000 --- a/moose-core/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/moose-core/scripts/moosegui b/moose-core/scripts/moosegui deleted file mode 100755 index 3acf2262e24990a7e3ffd8a496301b0ddf83e65a..0000000000000000000000000000000000000000 --- a/moose-core/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/moose-core/scripts/moosegui.py b/moose-core/scripts/moosegui.py deleted file mode 100755 index 40feef0c824f3cab0c2fdcae482baf030b6dccc0..0000000000000000000000000000000000000000 --- a/moose-core/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/moose-core/scripts/postinst b/moose-core/scripts/postinst deleted file mode 100755 index 11fdb89b1850299f47dfc5c6a76d13b684e69f85..0000000000000000000000000000000000000000 --- a/moose-core/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/moose-core/scripts/prerm b/moose-core/scripts/prerm deleted file mode 100755 index 3c976a65748cbd399ea44c3230bb7a313ea4e9f2..0000000000000000000000000000000000000000 --- a/moose-core/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/moose-core/scripts/submit.py b/moose-core/scripts/submit.py new file mode 100755 index 0000000000000000000000000000000000000000..931187361789959a7f6e31e5cc76bddd23d86414 --- /dev/null +++ b/moose-core/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/moose-core/shell/Shell.cpp b/moose-core/shell/Shell.cpp index aa7cc9831ef67209ae02853fddc9b5a5eba4ab87..1043f19d8b64af5eb157414ed15dd49b4a750603 100644 --- a/moose-core/shell/Shell.cpp +++ b/moose-core/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/moose-core/shell/Shell.h b/moose-core/shell/Shell.h index 40c36b3c36c71aaa289317f2bf86f84513bb8d43..1853a1ee640b989310af5ea245c2592462b1e8d0 100644 --- a/moose-core/shell/Shell.h +++ b/moose-core/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/moose-core/shell/Wildcard.cpp b/moose-core/shell/Wildcard.cpp index 9031759ac6484d1fd8c76956f9726f88f361ed86..abfb4f7de5fe6b55bc435b76217871e014a09b2c 100644 --- a/moose-core/shell/Wildcard.cpp +++ b/moose-core/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/moose-core/shell/Wildcard.h b/moose-core/shell/Wildcard.h index 912b37086b5a1b0e6b61409c0fe38cbd97e37875..1fd975789f25b6d1abeaac753134d99b0c2e4f3d 100644 --- a/moose-core/shell/Wildcard.h +++ b/moose-core/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/moose-core/tests/python/models.py b/moose-core/tests/python/models.py new file mode 100644 index 0000000000000000000000000000000000000000..3a5443f559e1ee361a83f094b9a7fe5cfa37b6f6 --- /dev/null +++ b/moose-core/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/moose-core/tests/python/test_moose_attribs.py b/moose-core/tests/python/test_moose_attribs.py index 4d3d97702aa3ffc97c6b72948b82c6d02914cd81..b10a2b30a4be8e81e56307da6cffcbaa6f793f07 100644 --- a/moose-core/tests/python/test_moose_attribs.py +++ b/moose-core/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/moose-core/tests/python/test_socket_streamer_tcp.py b/moose-core/tests/python/test_socket_streamer_tcp.py new file mode 100644 index 0000000000000000000000000000000000000000..497b66fb0412df6a1e454dca10ed19775bb1a59f --- /dev/null +++ b/moose-core/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/moose-core/tests/python/test_socket_streamer_uds.py b/moose-core/tests/python/test_socket_streamer_uds.py new file mode 100644 index 0000000000000000000000000000000000000000..542c3a46b212cb98f8218816a66bd31afecb2beb --- /dev/null +++ b/moose-core/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/moose-core/utility/setupenv.cpp b/moose-core/utility/setupenv.cpp index 3d8b32714927c705d733c3f49aca4a5414323368..422d3471d234fe051b1fcbb6d7c8f8f744ad176c 100644 --- a/moose-core/utility/setupenv.cpp +++ b/moose-core/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/moose-core/utility/strutil.cpp b/moose-core/utility/strutil.cpp index da5ee41f3516092a294567923297289fd92f8c5e..95b094509ff0467ccbfd89ce4a21cf35b3718295 100644 --- a/moose-core/utility/strutil.cpp +++ b/moose-core/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/moose-core/utility/strutil.h b/moose-core/utility/strutil.h index a5b1760b2c278fe7abde7aeaf52eab27e59bb38a..4d95c1419f2ce8fd197dc6ef0c292809f7c4be68 100644 --- a/moose-core/utility/strutil.h +++ b/moose-core/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/moose-core/utility/utility.h b/moose-core/utility/utility.h index 4d5510186b9b682233feca04b3487979728cee7c..ee0e88d7f1743de877bc0d09981b4d6c03c2e61c 100644 --- a/moose-core/utility/utility.h +++ b/moose-core/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