From f80ae40d5b1e1b63eb9849b9699d76f33e4f2572 Mon Sep 17 00:00:00 2001
From: Dilawar Singh <dilawars@ncbs.res.in>
Date: Sat, 16 Dec 2017 10:02:05 +0530
Subject: [PATCH] Squashed 'moose-core/' changes from 33d4803..bda9742

bda9742 Merge pull request #236 from upibhalla/master
86751f2 Added more accurate error messages to ZombieEnz for reporting missing messages during solver setup
5d93f75 Merge pull request #233 from upibhalla/master
cc47a2d Merge branch 'master' into master
a7ac8f4 Merge pull request #234 from BhallaLab/fix_travis_nov_30
5a08c96 pip is renamed to pip2. This commit passes on local machine.
bf8585d Possible fixes to travis build failure on osx.
f61a591 Added hack for channel not scaling when compartment size is scaled. Checks for child object called scaleFormula.
dff5731 Merge branch 'master' of https://github.com/BhallaLab/moose-core
7f0eb4b Merge pull request #231 from BhallaLab/prefix_python3
1d99906 Fix for spine ordering. Added capability to do unordered_map which may help with some of the performance issues during setup.
296c030 moose-core does not handle debian layout anymore. This should be handled in BhallaLab/moose.
0433574 commenting out changes introduced by 985af4e. Reopened BhallaLab/moose#224.

git-subtree-dir: moose-core
git-subtree-split: bda97426c899b2f366d08bdf30cf0f69876c9567
---
 .travis/travis_build_osx.sh     |  8 +++++--
 .travis/travis_prepare_osx.sh   | 14 +++++++-----
 CMakeLists.txt                  |  9 +++++---
 basecode/Id.h                   |  9 ++++++++
 basecode/header.h               |  1 +
 biophysics/CompartmentBase.cpp  | 11 +++++++++
 biophysics/Neuron.cpp           |  4 ++++
 ksolve/ZombieEnz.cpp            | 18 ++++++++++-----
 mesh/NeuroMesh.cpp              |  1 +
 mesh/NeuroNode.cpp              | 40 ++++++++++++++++++++++++++++-----
 mesh/NeuroNode.h                |  2 +-
 mesh/SpineMesh.cpp              |  1 +
 python/rdesigneur/rdesigneur.py | 14 ++++++------
 python/setup.cmake.py           | 24 +-------------------
 14 files changed, 103 insertions(+), 53 deletions(-)

diff --git a/.travis/travis_build_osx.sh b/.travis/travis_build_osx.sh
index e710a00e..f021ef26 100755
--- a/.travis/travis_build_osx.sh
+++ b/.travis/travis_build_osx.sh
@@ -21,10 +21,14 @@ set -o nounset                              # Treat unset variables as an error
 set -e
 
 (
-    mkdir -p _GSL_BUILD && cd _GSL_BUILD && cmake -DQUIET_MODE=ON -DDEBUG=ON -DPYTHON_EXECUTABLE=`which python` ..
+    mkdir -p _GSL_BUILD && cd _GSL_BUILD \
+        && cmake -DQUIET_MODE=ON -DDEBUG=ON \
+        -DPYTHON_EXECUTABLE=`which python` ..
     make && ctest --output-on-failure
     cd .. # Now with boost.
-    mkdir -p _BOOST_BUILD && cd _BOOST_BUILD && cmake -DWITH_BOOST=ON -DDEBUG=ON -DPYTHON_EXECUTABLE=`which python` ..
+    mkdir -p _BOOST_BUILD && cd _BOOST_BUILD \
+        && cmake -DWITH_BOOST=ON -DDEBUG=ON \
+        -DPYTHON_EXECUTABLE=`which python` ..
     make && ctest --output-on-failure
     cd ..
 )
diff --git a/.travis/travis_prepare_osx.sh b/.travis/travis_prepare_osx.sh
index 61fdea5b..b7e0fe3f 100755
--- a/.travis/travis_prepare_osx.sh
+++ b/.travis/travis_prepare_osx.sh
@@ -19,17 +19,19 @@
 
 set -o nounset                              # Treat unset variables as an error
 set +e
-rvm get head
-brew update
+#rvm get head
+#brew update
 #brew outdated cmake || brew install cmake
 brew install gsl
 brew install hdf5
-brew install homebrew/science/libsbml
+brew install python
+brew install numpy
 #brew outdated python || brew install python
 #brew outdated numpy || brew install homebrew/python/numpy
-#brew unlink numpy && brew link numpy || echo "Failed to link numpy"
+brew unlink numpy && brew link numpy || echo "Failed to link numpy"
 # Numpy caveats
 mkdir -p $HOME/Library/Python/2.7/lib/python/site-packages
 echo 'import sys; sys.path.insert(1, "/usr/local/lib/python2.7/site-packages")' >> $HOME/Library/Python/2.7/lib/python/site-packages/homebrew.pth
-pip install matplotlib
-
+# ensurepip
+#python -m ensurepip
+pip2 install matplotlib --user
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e6a29043..b3370255 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -408,9 +408,12 @@ message( STATUS "Platform ${_platform_desc}" )
 
 set(EXTRA_ARGS "--prefix ${CMAKE_INSTALL_PREFIX}")
 
-if( ${_platform_desc} MATCHES ".*(Ubuntu|Debian).*" )
-    list( APPEND EXTRA_ARGS "--install-layout=deb" )
-endif( )
+## NOTE: Disable it here. It must be handled by moose repository CMakeLists.txt
+## which is used in created packages. For normal user, it should install in
+## site-packages.
+#if( ${_platform_desc} MATCHES ".*(Ubuntu|Debian).*" )
+#    list( APPEND EXTRA_ARGS "--install-layout=deb" )
+#endif( )
 
 # If make is called with sudo, install in system directories. Otherwise use
 # --user to install in user home.
diff --git a/basecode/Id.h b/basecode/Id.h
index 04bb3152..9aed5e9b 100644
--- a/basecode/Id.h
+++ b/basecode/Id.h
@@ -174,4 +174,13 @@ private:
     static vector< Element* >& elements();
 };
 
+namespace std {
+	template <> class hash<Id>{
+			public :
+			size_t operator()(const Id &x ) const{
+			return hash<unsigned int>()( x.value() );
+		}
+	};
+}
+
 #endif // _ID_H
diff --git a/basecode/header.h b/basecode/header.h
index 62956004..595b7f26 100644
--- a/basecode/header.h
+++ b/basecode/header.h
@@ -16,6 +16,7 @@
 #include <vector>
 #include <string>
 #include <map>
+#include <unordered_map>
 #include <iostream>
 #include <sstream>
 #include <typeinfo> // used in Conv.h to extract compiler independent typeid
diff --git a/biophysics/CompartmentBase.cpp b/biophysics/CompartmentBase.cpp
index 94ac948d..1528f54f 100644
--- a/biophysics/CompartmentBase.cpp
+++ b/biophysics/CompartmentBase.cpp
@@ -636,6 +636,15 @@ void CompartmentBase::displace( double dx, double dy, double dz )
 	z_ += dz;
 }
 
+static bool hasScaleFormula( const Eref& e ) {
+	vector< Id > kids;
+	Neutral::children( e, kids );
+	for ( vector< Id >::iterator j = kids.begin(); j != kids.end(); j++ )
+		if ( j->element()->getName() == "scaleFormula" )
+			return true;
+	return false;
+}
+
 void CompartmentBase::setGeomAndElec( const Eref& e,
 				double len, double dia )
 {
@@ -650,6 +659,8 @@ void CompartmentBase::setGeomAndElec( const Eref& e,
 		vector< ObjId > chans;
 		allChildren( e.objId(), ALLDATA, "ISA=ChanBase", chans );
 		for ( unsigned int i = 0; i < chans.size(); ++i ) {
+			if ( hasScaleFormula( chans[i].eref() ) )
+				continue; // Later we will eval the formula with len and dia
 			double gbar = Field< double >::get( chans[i], "Gbar" );
 			gbar *= len * dia / ( length_ * diameter_ );
 			Field< double >::set( chans[i], "Gbar", gbar );
diff --git a/biophysics/Neuron.cpp b/biophysics/Neuron.cpp
index 26563573..6a5e42d3 100644
--- a/biophysics/Neuron.cpp
+++ b/biophysics/Neuron.cpp
@@ -1111,6 +1111,7 @@ void Neuron::buildElist( const Eref& e,
     ObjId oldCwe = shell->getCwe();
     shell->setCwe( e.objId() );
     wildcardFind( path, elist );
+	sort( elist.begin(), elist.end() );
     shell->setCwe( oldCwe );
     evalExprForElist( elist, expr, val );
 }
@@ -1285,6 +1286,8 @@ static void fillSegments( vector< SwcSegment >& segs,
                     comptType = 3; // generic dendrite
                 }
             }
+			// cout << "Seg[" << i << "].xy = " << int(x*1e6) << " " << int(y*1e6) << endl;
+
             segs.push_back(
                 SwcSegment( i, comptType, x, y, z, dia/2.0, paIndex ) );
         }
@@ -1347,6 +1350,7 @@ void Neuron::buildSegmentTree( const Eref& e )
 {
     vector< Id > kids;
     Neutral::children( e, kids );
+	sort( kids.begin(), kids.end() );
 
     soma_ = fillSegIndex( kids, segIndex_ );
     if ( kids.size() == 0 || soma_ == Id() )
diff --git a/ksolve/ZombieEnz.cpp b/ksolve/ZombieEnz.cpp
index 8e56b9c7..361ac111 100644
--- a/ksolve/ZombieEnz.cpp
+++ b/ksolve/ZombieEnz.cpp
@@ -224,22 +224,28 @@ void ZombieEnz::setSolver( Id stoich, Id enz )
 	bool isOK = true;
 	unsigned int numReactants;
 	numReactants = enz.element()->getNeighbors( enzMols, enzFinfo );
-	isOK &= ( numReactants == 1 );
+	bool hasEnz = ( numReactants == 1 );
 	vector< Id > subs;
 	numReactants = enz.element()->getNeighbors( subs, subFinfo );
-	isOK &= ( numReactants > 0 );
+	bool hasSubs = ( numReactants > 0 );
 	numReactants = enz.element()->getNeighbors( cplxMols, cplxFinfo );
-	isOK &= ( numReactants == 1 );
+	bool hasCplx = ( numReactants == 1 );
 	vector< Id > prds;
 	numReactants = enz.element()->getNeighbors( prds, prdFinfo );
-	isOK &= ( numReactants > 0 );
+	bool hasPrds = ( numReactants > 0 );
 	assert( stoich.element()->cinfo()->isA( "Stoich" ) );
 	stoich_ = reinterpret_cast< Stoich* >( stoich.eref().data() );
 
-	if ( isOK ) {
+	if ( hasEnz && hasSubs && hasCplx && hasPrds ) {
 		stoich_->installEnzyme( enz, enzMols[0], cplxMols[0], subs, prds );
 	} else {
 		stoich_->installDummyEnzyme( enz, Id() );
-		cout << "Warning: ZombieEnz:setSolver: Dangling Enz, missing a substrate or product\n";
+		string msg = "";
+		if ( !hasEnz ) msg = msg + " enzyme";
+		if ( !hasCplx ) msg = msg + " enzyme-substrate complex";
+		if ( !hasSubs ) msg = msg + " substrates";
+		if ( !hasPrds ) msg = msg + " products";
+		cout << "Warning: ZombieEnz:setSolver: Dangling Enz '" <<
+			enz.path() << "':\nMissing " << msg << endl;
 	}
 }
diff --git a/mesh/NeuroMesh.cpp b/mesh/NeuroMesh.cpp
index 968c6c83..2cf28411 100644
--- a/mesh/NeuroMesh.cpp
+++ b/mesh/NeuroMesh.cpp
@@ -648,6 +648,7 @@ void NeuroMesh::updateShaftParents()
 // Uses all compartments, and if they have spines on them adds those too.
 void NeuroMesh::setSubTree( const Eref& e, vector< ObjId > compts )
 {
+    sort( compts.begin(), compts.end() );
     if ( separateSpines_ )
     {
         NeuroNode::buildSpinyTree( compts, nodes_, shaft_, head_, parent_);
diff --git a/mesh/NeuroNode.cpp b/mesh/NeuroNode.cpp
index 6afac30e..9e86634a 100644
--- a/mesh/NeuroNode.cpp
+++ b/mesh/NeuroNode.cpp
@@ -427,7 +427,7 @@ static bool checkForSpine( unsigned int dendIndex, Id compt,
  *
  */
 static void spinyTraverse( unsigned int dendIndex,
-	vector< Id >& dend, const map< Id, unsigned int >& dendMap,
+	vector< Id >& dend, const unordered_map< Id, unsigned int >& dendMap,
 	vector< int >& seen, unsigned int numSeen,
 	vector< Id >& shaftId, vector< Id >& headId,
 	vector< int >& dendParent, vector< unsigned int >& spineParent
@@ -436,7 +436,7 @@ static void spinyTraverse( unsigned int dendIndex,
 	vector< Id > conn = findAllConnectedCompartments( dend[dendIndex] );
 	seen[ dendIndex ] = numSeen;
 	for ( vector< Id >::iterator i = conn.begin(); i != conn.end(); ++i ) {
-		map< Id, unsigned int >::const_iterator idLookup =
+		unordered_map< Id, unsigned int >::const_iterator idLookup =
 				dendMap.find( *i );
 		if ( idLookup != dendMap.end() ) {
 			if ( !seen[ idLookup->second ] ) {
@@ -451,6 +451,32 @@ static void spinyTraverse( unsigned int dendIndex,
 	}
 }
 
+// Takes all 3 arrays, gets an array of indices that sorts them by shaftId,
+// and then uses it to sort them all.
+// Based on a post by quantdev on StackOverflow.
+static void sortByShaftIds( vector< Id >& shaftId, vector< Id >& headId,
+	vector< unsigned int >& spineParent )
+{
+	size_t sortedIndex(0);
+	vector<int> y(shaftId.size());
+	generate(begin(y), end(y), [&]{ return sortedIndex++; });
+	sort(  begin(y), end(y),
+		[&](int i1, int i2) { return shaftId[i1] < shaftId[i2]; } );
+
+	assert( sortedIndex == shaftId.size() );
+	assert( sortedIndex == headId.size() );
+	assert( sortedIndex == spineParent.size() );
+
+	auto a = shaftId;
+	auto b = headId;
+	auto c = spineParent;
+	for ( size_t i = 0; i < sortedIndex; ++i) {
+		shaftId[i] = a[y[i]];
+		headId[i] = b[y[i]];
+		spineParent[i] = c[y[i]];
+	}
+}
+
 /**
  * This function takes a list of elements and builds a tree.
  * Info on any attached spines are placed in the
@@ -469,12 +495,13 @@ void NeuroNode::buildSpinyTree(
 {
 	nodes.clear();
 	sort( elist.begin(), elist.end() );
-	map< Id, unsigned int > dendMap;
+	unordered_map< Id, unsigned int > dendMap;
 	vector< Id > dend;
 	for ( vector< ObjId >::iterator
 		i = elist.begin(); i != elist.end(); ++i ) {
 		if ( isPartOfDend( *i ) ) {
 			dendMap[ *i ] = dend.size();
+			//cout << "st: dendMap[" << *i << "] = " << dend.size() << endl;
 			dend.push_back( *i );
 		}
 	}
@@ -487,6 +514,9 @@ void NeuroNode::buildSpinyTree(
 			shaftId, headId,
 			dendParent, spineParent );
 	}
+	// Here I sort by shaftIds. I have 4 parallel arrays, so I get the
+	// Index order of the whole lot that will sort the shaftIds.
+	sortByShaftIds( shaftId, headId, spineParent );
 	if ( numSeen == 0 )
 		return;
 	for ( unsigned int i = 0; i < dend.size(); ++i )
@@ -501,10 +531,10 @@ void NeuroNode::buildSpinyTree(
 }
 
 void NeuroNode::setParentAndChildren( unsigned int index, int dendParent,
-	vector< NeuroNode >& nodes, const map< Id, unsigned int >& dendMap )
+	vector< NeuroNode >& nodes, const unordered_map< Id, unsigned int >& dendMap )
 {
 	parent_ = dendParent;
-	const map< Id, unsigned int >::const_iterator dendLookup =
+	const unordered_map< Id, unsigned int >::const_iterator dendLookup =
 			dendMap.find( nodes[dendParent].elecCompt_ );
 	if ( dendLookup != dendMap.end() ) {
 		assert( dendLookup->second < nodes.size() );
diff --git a/mesh/NeuroNode.h b/mesh/NeuroNode.h
index bb6b5aac..9c784fcb 100644
--- a/mesh/NeuroNode.h
+++ b/mesh/NeuroNode.h
@@ -165,7 +165,7 @@ class NeuroNode: public CylBase
 					vector< unsigned int >& spineParent );
 		void setParentAndChildren( unsigned int index, int dendParent,
 				vector< NeuroNode >& nodes,
-				const map< Id, unsigned int >& dendMap );
+				const unordered_map< Id, unsigned int >& dendMap );
 
 		/**
 		 * Trims off all spines from tree. Does so by identifying a set of
diff --git a/mesh/SpineMesh.cpp b/mesh/SpineMesh.cpp
index a09c3ccd..4fca0872 100644
--- a/mesh/SpineMesh.cpp
+++ b/mesh/SpineMesh.cpp
@@ -260,6 +260,7 @@ void SpineMesh::handleSpineList(
 		vector< unsigned int > index( head.size(), 0 );
 		for ( unsigned int i = 0; i < head.size(); ++i ) {
 			spines_[i] = SpineEntry( shaft[i], head[i], parentVoxel[i] );
+			// cout << i << "	" << head[i] << ", pa = " << parentVoxel[i] << endl;
 			// ret = spines_[i].psdCoords();
 			// assert( ret.size() == 8 );
 			// psdCoords.insert( psdCoords.end(), ret.begin(), ret.end() );
diff --git a/python/rdesigneur/rdesigneur.py b/python/rdesigneur/rdesigneur.py
index 375fe76d..8665281d 100644
--- a/python/rdesigneur/rdesigneur.py
+++ b/python/rdesigneur/rdesigneur.py
@@ -527,9 +527,14 @@ class rdesigneur:
             cc = moose.element( self.modelPath + '/chem/' + chemCompt)
             voxelVec = []
             temp = [ self._makeUniqueNameStr( i ) for i in comptList ]
+            #print( temp )
+            #print( "#####################" )
             comptSet = set( temp )
             #em = [ moose.element(i) for i in cc.elecComptMap ]
-            em = [ self._makeUniqueNameStr(i) for i in cc.elecComptMap ]
+            em = sorted( [ self._makeUniqueNameStr(i[0]) for i in cc.elecComptMap ] )
+            #print( em )
+            #print( "=================================================" )
+
             voxelVec = [i for i in range(len( em ) ) if em[i] in comptSet ]
             # Here we collapse the voxelVec into objects to plot.
             allObj = moose.vec( self.modelPath + '/chem/' + plotSpec[2] )
@@ -574,6 +579,7 @@ class rdesigneur:
             assert( plotField == plotField2 )
             plotObj3 = plotObj + plotObj2
             numPlots = sum( q != dummy for q in plotObj3 )
+            #print( "PlotList: {0}: numobj={1}, field ={2}, nd={3}, ns={4}".format( pair, numPlots, plotField, len( dendCompts ), len( spineCompts ) ) )
             if numPlots > 0:
                 tabname = graphs.path + '/plot' + str(k)
                 scale = knownFields[i[3]][2]
@@ -911,7 +917,6 @@ class rdesigneur:
     ################################################################
     # Utility function for setting up clocks.
     def _configureClocks( self ):
-        t0 = time.time()
         if self.turnOffElec:
             elecDt = 1e6
             elecPlotDt = 1e6
@@ -920,21 +925,16 @@ class rdesigneur:
             elecPlotDt = self.elecPlotDt
         diffDt = self.diffDt
         chemDt = self.chemDt
-        print( "t1 = {}".format( time.time() - t0 ) )
         for i in range( 0, 9 ):
             moose.setClock( i, elecDt )
         moose.setClock( 8, elecPlotDt )
         moose.setClock( 10, diffDt )
-        print( "t2 = {}".format( time.time() - t0 ) )
         for i in range( 11, 18 ):
             moose.setClock( i, chemDt )
         moose.setClock( 18, self.chemPlotDt )
-        print( "t3 = {}".format( time.time() - t0 ) )
         hsolve = moose.HSolve( self.elecid.path + '/hsolve' )
         hsolve.dt = elecDt
-        print( "t4 = {}".format( time.time() - t0 ) )
         hsolve.target = self.soma.path
-        print( "t5 = {}".format( time.time() - t0 ) )
         sys.stdout.flush()
     ################################################################
     ################################################################
diff --git a/python/setup.cmake.py b/python/setup.cmake.py
index 5be00881..54bcc425 100644
--- a/python/setup.cmake.py
+++ b/python/setup.cmake.py
@@ -18,33 +18,11 @@ __status__           = "Development"
 
 import os
 import sys
-import site
-
-# if uid is zero then install in root paths. Else install it in user path.
-
-print( '[INFO] Overwriting --prefix ' )
-try:
-    prefixLoc = sys.argv.index( '--prefix' )
-    del sys.argv[ prefixLoc ]
-    del sys.argv[ prefixLoc ]
-except Exception as e:
-    pass
-
-uid = os.getuid( )
-if uid == 0:
-    # Here comes the root.
-    print( '   called by sudo' )
-    sys.argv += [ '--prefix', '/usr' ]
-else:
-    sys.argv += [ '--prefix', site.getuserbase( ) ]
-
-print( sys.argv )
 
 from distutils.core import setup
-
 script_dir = os.path.dirname( os.path.abspath( __file__ ) )
-
 version = '3.2.git'
+
 try:
     with open( os.path.join( script_dir, '..', 'VERSION'), 'r' ) as f:
         version = f.read( )
-- 
GitLab