Skip to content
Snippets Groups Projects
Select Git revision
  • 37d039759ef32ed15fca7b5c84f1ca34d6064fa1
  • master default protected
  • tut_ring_allen
  • docs_furo
  • docs_reorder_cable_cell
  • docs_graphviz
  • docs_rtd_dev
  • ebrains_mirror
  • doc_recat
  • docs_spike_source
  • docs_sim_sample_clar
  • docs_pip_warn
  • github_template_updates
  • docs_fix_link
  • cv_default_and_doc_clarification
  • docs_add_numpy_req
  • readme_zenodo_05
  • install_python_fix
  • install_require_numpy
  • typofix_propetries
  • docs_recipe_lookup
  • v0.10.0
  • v0.10.1
  • v0.10.0-rc5
  • v0.10.0-rc4
  • v0.10.0-rc3
  • v0.10.0-rc2
  • v0.10.0-rc
  • v0.9.0
  • v0.9.0-rc
  • v0.8.1
  • v0.8
  • v0.8-rc
  • v0.7
  • v0.6
  • v0.5.2
  • v0.5.1
  • v0.5
  • v0.4
  • v0.3
  • v0.2.2
41 results

linearrewriter.hpp

Blame
  • SpineMesh.cpp 15.91 KiB
    /**********************************************************************
    ** This program is part of 'MOOSE', the
    ** Messaging Object Oriented Simulation Environment.
    **           Copyright (C) 2013 Upinder S. Bhalla. and NCBS
    ** It is made available under the terms of the
    ** GNU Lesser General Public License version 2.1
    ** See the file COPYING.LIB for the full notice.
    **********************************************************************/
    
    #include <cctype>
    #include "header.h"
    #include "SparseMatrix.h"
    #include "../utility/Vec.h"
    
    #include "ElementValueFinfo.h"
    #include "Boundary.h"
    #include "MeshEntry.h"
    #include "ChemCompt.h"
    #include "MeshCompt.h"
    #include "CubeMesh.h"
    #include "CylBase.h"
    #include "NeuroNode.h"
    #include "NeuroMesh.h"
    #include "SpineEntry.h"
    #include "SpineMesh.h"
    #include "PsdMesh.h"
    #include "../utility/numutil.h"
    
    /*
    static SrcFinfo3< Id, vector< double >, vector< unsigned int > >* 
    	psdListOut()
    {
    	static SrcFinfo3< Id, vector< double >, vector< unsigned int > >
       		psdListOut(
    		"psdListOut",
    		"Tells PsdMesh to build a mesh. "
    		"Arguments: Coordinates of each psd, "
    		"index of matching parent voxels for each spine"
    		"The coordinates each have 8 entries:"
    		"xyz of centre of psd, xyz of vector perpendicular to psd, "
    		"psd diameter, "
    		" diffusion distance from parent compartment to PSD"
    	);
    	return &psdListOut;
    }
    */
    
    const Cinfo* SpineMesh::initCinfo()
    {
    		//////////////////////////////////////////////////////////////
    		// Field Definitions
    		//////////////////////////////////////////////////////////////
    		static ReadOnlyValueFinfo< SpineMesh, vector< unsigned int > >
    			parentVoxel 
    		(
    		 	"parentVoxel",
    			"Vector of indices of proximal voxels within this mesh."
    			"Spines are at present modeled with just one compartment,"
    			"so each entry in this vector is always set to EMPTY == -1U",
    			&SpineMesh::getParentVoxel
    		);
    
    		static ReadOnlyValueFinfo< SpineMesh, vector< unsigned int > >
    			neuronVoxel 
    		(
    		 	"neuronVoxel",
    			"Vector of indices of voxels on parent NeuroMesh, from which "
    			"the respective spines emerge.",
    			&SpineMesh::getNeuronVoxel
    		);
    
    		static ReadOnlyValueFinfo< SpineMesh, vector< Id > > elecComptMap(
    			"elecComptMap",
    			"Vector of Ids of electrical compartments that map to each "
    			"voxel. This is necessary because the order of the IDs may "
    			"differ from the ordering of the voxels. Note that there "
    			"is always just one voxel per spine head. ",
    			&SpineMesh::getElecComptMap
    		);
    		static ReadOnlyValueFinfo< SpineMesh, vector< Id > > elecComptList(
    			"elecComptList",
    			"Vector of Ids of all electrical compartments in this "
    			"SpineMesh. Ordering is as per the tree structure built in "
    			"the NeuroMesh, and may differ from Id order. Ordering "
    			"matches that used for startVoxelInCompt and endVoxelInCompt",
    			&SpineMesh::getElecComptMap
    		);
    		static ReadOnlyValueFinfo< SpineMesh, vector< unsigned int > > startVoxelInCompt(
    			"startVoxelInCompt",
    			"Index of first voxel that maps to each electrical "
    			"compartment. This is a trivial function in the SpineMesh, as"
    			"we have a single voxel per spine. So just a vector of "
    			"its own indices.",
    			&SpineMesh::getStartVoxelInCompt
    		);
    		static ReadOnlyValueFinfo< SpineMesh, vector< unsigned int > > endVoxelInCompt(
    			"endVoxelInCompt",
    			"Index of end voxel that maps to each electrical "
    			"compartment. Since there is just one voxel per electrical "
    			"compartment in the spine, this is just a vector of index+1",
    			&SpineMesh::getEndVoxelInCompt
    		);
    
    		//////////////////////////////////////////////////////////////
    		// MsgDest Definitions
    		//////////////////////////////////////////////////////////////
    
    		static DestFinfo spineList( "spineList",
    			"Specifies the list of electrical compartments for the spine,"
    			"and the associated parent voxel"
    			"Arguments: shaft compartments, "
    			"head compartments, parent voxel index ",
    			new EpFunc3< SpineMesh, vector< Id >, vector< Id >,
    		   	vector< unsigned int > >(
    				&SpineMesh::handleSpineList )
    		);
    
    		//////////////////////////////////////////////////////////////
    		// Field Elements
    		//////////////////////////////////////////////////////////////
    
    	static Finfo* spineMeshFinfos[] = {
    		&parentVoxel,		// ReadOnlyValueFinfo
    		&neuronVoxel,		// ReadOnlyValueFinfo
    		&elecComptMap,		// ReadOnlyValueFinfo
    		&elecComptList,		// ReadOnlyValueFinfo
    		&startVoxelInCompt,		// ReadOnlyValueFinfo
    		&endVoxelInCompt,		// ReadOnlyValueFinfo
    		&spineList,			// DestFinfo
    		// psdListOut(),		// SrcFinfo
    	};
    
    	static Dinfo< SpineMesh > dinfo;
    	static Cinfo spineMeshCinfo (
    		"SpineMesh",
    		ChemCompt::initCinfo(),
    		spineMeshFinfos,
    		sizeof( spineMeshFinfos ) / sizeof ( Finfo* ),
    		&dinfo
    	);
    
    	return &spineMeshCinfo;
    }
    
    //////////////////////////////////////////////////////////////
    // Basic class Definitions
    //////////////////////////////////////////////////////////////
    
    static const Cinfo* spineMeshCinfo = SpineMesh::initCinfo();
    
    //////////////////////////////////////////////////////////////////
    // Class stuff.
    //////////////////////////////////////////////////////////////////
    SpineMesh::SpineMesh()
    	:
    		spines_( 1 ),
    		surfaceGranularity_( 0.1 ),
    		vs_( 1, 1.0e-18 ),
    		area_( 1, 1.0e-12 ),
    		length_( 1, 1.0e-6 )
    {;}
    
    SpineMesh::SpineMesh( const SpineMesh& other )
    	: 
    		spines_( other.spines_ ),
    		surfaceGranularity_( other.surfaceGranularity_ )
    {;}
    
    SpineMesh::~SpineMesh()
    {
    	;
    }
    
    //////////////////////////////////////////////////////////////////
    // Field assignment stuff
    //////////////////////////////////////////////////////////////////
    
    /**
     * This function returns the diffusively connected parent voxel within
     * the current (spine) mesh. Since each spine is treated as an independed
     * voxel, there is no such voxel, so we return -1U for each spine.
     * Note that there is a separate function that returns the parentVoxel
     * referred to the NeuroMesh that this spine sits on.
     */
    vector< unsigned int > SpineMesh::getParentVoxel() const
    {
    	vector< unsigned int > ret( spines_.size(), -1U );
    	// for ( unsigned int i = 0; i < spines_.size(); ++i ) 
    	// 	ret[i] = spines_[i].parent(); // Wrong, returns voxel on NeuroMesh
    	return ret;
    }
    
    /**
     * Returns index of voxel on NeuroMesh to which this spine is connected.
     */
    vector< unsigned int > SpineMesh::getNeuronVoxel() const
    {
    	vector< unsigned int > ret( spines_.size(), -1U );
    	for ( unsigned int i = 0; i < spines_.size(); ++i ) 
    		ret[i] = spines_[i].parent();
    	return ret;
    }
    
    vector< Id > SpineMesh::getElecComptMap() const
    {
    	vector< Id > ret( spines_.size() );
    	for ( unsigned int i = 0; i < spines_.size(); ++i ) 
    		ret[i] = spines_[i].headId();
    	return ret;
    }
    
    vector< unsigned int > SpineMesh::getStartVoxelInCompt() const
    {
    	vector< unsigned int > ret( spines_.size() );
    	for ( unsigned int i = 0; i < ret.size(); ++i ) 
    		ret[i] = i;
    	return ret;
    }
    
    vector< unsigned int > SpineMesh::getEndVoxelInCompt() const
    {
    	vector< unsigned int > ret( spines_.size() );
    	for ( unsigned int i = 0; i < ret.size(); ++i ) 
    		ret[i] = i+1;
    	return ret;
    }
    
    //////////////////////////////////////////////////////////////////////
    
    /**
     * This assumes that lambda is the quantity to preserve, over numEntries.
     * So when the compartment changes volume, numEntries changes too.
     * Assumes that the soma node is at index 0.
     */
    void SpineMesh::updateCoords()
    {
    	buildStencil();
    }
    
    unsigned int SpineMesh::innerGetDimensions() const
    {
    	return 3;
    }
    
    // Here we set up the spines. We don't permit heads without shafts.
    void SpineMesh::handleSpineList( 
    		const Eref& e, vector< Id > shaft, vector< Id > head, 
    		vector< unsigned int > parentVoxel )
    {
    		double oldVol = getMeshEntryVolume( 0 );
    		assert( head.size() == parentVoxel.size() );
    		assert( head.size() == shaft.size() );
    		spines_.resize( head.size() );
    		vs_.resize( head.size() );
    		area_.resize( head.size() );
    		length_.resize( head.size() );
    
    		vector< double > ret;
    		vector< double > psdCoords;
    		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] );
    			// ret = spines_[i].psdCoords();
    			// assert( ret.size() == 8 );
    			// psdCoords.insert( psdCoords.end(), ret.begin(), ret.end() );
    			// index[i] = i;
    			vs_[i] = spines_[i].volume();
    			area_[i] = spines_[i].rootArea();
    			length_[i] = spines_[i].diffusionLength();
    		}
    
    		updateCoords();
    		Id meshEntry( e.id().value() + 1 );
    		
    		vector< unsigned int > localIndices( head.size() );
    		vector< double > vols( head.size() );
    		for ( unsigned int i = 0; i < head.size(); ++i ) {
    			localIndices[i] = i;
    			vols[i] = spines_[i].volume();
    		}
    		vector< vector< unsigned int > > outgoingEntries;
    		vector< vector< unsigned int > > incomingEntries;
    		// meshSplit()->send( e, oldVol, vols, localIndices, outgoingEntries, incomingEntries );
    		lookupEntry( 0 )->triggerRemesh( meshEntry.eref(),
    						oldVol, 0, localIndices, vols );
    }
    
    //////////////////////////////////////////////////////////////////
    // FieldElement assignment stuff for MeshEntries
    //////////////////////////////////////////////////////////////////
    
    /// Virtual function to return MeshType of specified entry.
    unsigned int SpineMesh::getMeshType( unsigned int fid ) const
    {
    	assert( fid < spines_.size() );
    	return CYL;
    }
    
    /// Virtual function to return dimensions of specified entry.
    unsigned int SpineMesh::getMeshDimensions( unsigned int fid ) const
    {
    	return 3;
    }
    
    /// Virtual function to return volume of mesh Entry.
    double SpineMesh::getMeshEntryVolume( unsigned int fid ) const
    {
    	if ( spines_.size() == 0 )
    		return 1.0;
    	assert( fid < spines_.size() );
    	return spines_[ fid % spines_.size() ].volume();
    }
    /// Virtual function to assign volume of mesh Entry.
    void SpineMesh::setMeshEntryVolume( unsigned int fid, double volume ) 
    {
    	if ( spines_.size() == 0 )
    		return;
    	assert( fid < spines_.size() );
    	spines_[ fid % spines_.size() ].setVolume( volume );
    }
    
    /// Virtual function to return coords of mesh Entry.
    /// For SpineMesh, coords are x1y1z1 x2y2z2 x3y3z3 r0 r1
    vector< double > SpineMesh::getCoordinates( unsigned int fid ) const
    {
    	vector< double > ret;
    	return ret;
    }
    
    /// Virtual function to return diffusion X-section area for each neighbor
    vector< double > SpineMesh::getDiffusionArea( unsigned int fid ) const
    {
    	vector< double > ret;
    	return ret;
    }
    
    /// Virtual function to return scale factor for diffusion.
    /// I think all dendite tips need to return just one entry of 1.
    //  Regular points return vector( 2, 1.0 );
    vector< double > SpineMesh::getDiffusionScaling( unsigned int fid ) const
    {
    	return vector< double >( 2, 1.0 );
    }
    
    /// Virtual function to return volume of mesh Entry, including
    /// for diffusively coupled voxels from other solvers.
    double SpineMesh::extendedMeshEntryVolume( unsigned int fid ) const
    {
    	if ( fid < spines_.size() ) {
    		return getMeshEntryVolume( fid );
    	} else {
    		return MeshCompt::extendedMeshEntryVolume( fid - spines_.size() );
    	}
    }
    
    
    
    //////////////////////////////////////////////////////////////////
    // Dest funcsl
    //////////////////////////////////////////////////////////////////
    
    /*
    /// More inherited virtual funcs: request comes in for mesh stats
    /// Not clear what this does.
    void SpineMesh::innerHandleRequestMeshStats( const Eref& e,
    		const SrcFinfo2< unsigned int, vector< double > >* meshStatsFinfo
    	)
    {
    		;
    }
    */
    
    void SpineMesh::innerHandleNodeInfo(
    			const Eref& e,
    			unsigned int numNodes, unsigned int numThreads )
    {
    
    
    }
    //////////////////////////////////////////////////////////////////
    // Inherited virtual funcs
    //////////////////////////////////////////////////////////////////
    
    const vector< double >& SpineMesh::vGetVoxelVolume() const
    {
    	return vs_;
    }
    
    const vector< double >& SpineMesh::vGetVoxelMidpoint() const
    {
    	static vector< double > midpoint;
    	midpoint.resize( spines_.size() * 3 );
    	for ( unsigned int i = 0; i < spines_.size(); ++i ) {
    		spines_[i].mid( midpoint[i], 
    						midpoint[i + spines_.size() ], 
    						midpoint[i + 2 * spines_.size() ] 
    		); 
    	}
    	return midpoint;
    }
    
    const vector< double >& SpineMesh::getVoxelArea() const
    {
    	return area_;
    }
    
    const vector< double >& SpineMesh::getVoxelLength() const
    {
    	return length_;
    }
    
    double SpineMesh::vGetEntireVolume() const
    {
    	double ret = 0.0;
    	for ( vector< double >::const_iterator i = 
    					vs_.begin(); i != vs_.end(); ++i )
    		ret += *i;
    	return ret;
    }
    
    bool SpineMesh::vSetVolumeNotRates( double volume )
    {
    	double volscale = volume / vGetEntireVolume();
    	double linscale = pow( volscale, 1.0/3.0 );
    	assert( vs_.size() == spines_.size() );
    	assert( area_.size() == spines_.size() );
    	assert( length_.size() == spines_.size() );
    	for ( unsigned int i = 0; i < spines_.size(); ++i ) {
    		spines_[i].setVolume( volume );
    		vs_[i] *= volscale;
    		area_[i] *= linscale * linscale;
    		length_[i] *= linscale;
    	}
    	return true;
    }
    
    //////////////////////////////////////////////////////////////////
    
    /**
     * Inherited virtual func. Returns number of MeshEntry in array
     */
    unsigned int SpineMesh::innerGetNumEntries() const
    {
    	return spines_.size();
    }
    
    /**
     * Inherited virtual func. Assigns number of MeshEntries.
     * Doesn't do anything, we have to set spine # from geometry.
     */
    void SpineMesh::innerSetNumEntries( unsigned int n )
    {
    }
    
    
    /**
     * Not allowed.
     */
    void SpineMesh::innerBuildDefaultMesh( const Eref& e,
    	double volume, unsigned int numEntries )
    {
    	cout << "Warning: SpineMesh::innerBuildDefaultMesh: attempt to build a default spine: not permitted\n";
    }
    
    //////////////////////////////////////////////////////////////////
    const vector< SpineEntry >& SpineMesh::spines() const
    {
    		return spines_;
    }
    
    //////////////////////////////////////////////////////////////////
    // Utility function to set up Stencil for diffusion
    //////////////////////////////////////////////////////////////////
    void SpineMesh::buildStencil()
    {
    // stencil_[0] = new NeuroStencil( nodes_, nodeIndex_, vs_, area_);
    	setStencilSize( spines_.size(), spines_.size() );
    	innerResetStencil();
    }
    
    //////////////////////////////////////////////////////////////////
    // Utility function for junctions
    //////////////////////////////////////////////////////////////////
    
    void SpineMesh::matchMeshEntries( const ChemCompt* other,
    	   vector< VoxelJunction >& ret ) const
    {
    	const CubeMesh* cm = dynamic_cast< const CubeMesh* >( other );
    	if ( cm ) {
    		matchCubeMeshEntries( other, ret );
    		return;
    	}
    	const NeuroMesh* nm = dynamic_cast< const NeuroMesh* >( other );
    	if ( nm ) {
    		matchNeuroMeshEntries( other, ret );
    		return;
    	}
    	const PsdMesh* pm = dynamic_cast< const PsdMesh* >( other );
    	if ( pm ) {
    		pm->matchSpineMeshEntries( this, ret );
    		flipRet( ret );
    		return;
    	}
    	cout << "Warning: SpineMesh::matchMeshEntries: unknown class\n";
    }
    
    void SpineMesh::indexToSpace( unsigned int index,
    			double& x, double& y, double& z ) const 
    {
    	if ( index >= innerGetNumEntries() )
    		return;
    	spines_[ index ].mid( x, y, z );
    }
    
    double SpineMesh::nearest( double x, double y, double z, 
    				unsigned int& index ) const
    {
    	double best = 1e12;
    	index = 0;
    	for( unsigned int i = 0; i < spines_.size(); ++i ) {
    		const SpineEntry& se = spines_[i];
    		double a0, a1, a2;
    		se.mid( a0, a1, a2 );
    		Vec a( a0, a1, a2 );
    		Vec b( x, y, z );
    		double d = a.distance( b );
    		if ( best > d ) {
    			best = d;
    			index = i;
    		}
    	}
    	if ( best == 1e12 )
    		return -1;
    	return best;
    }
    
    void SpineMesh::matchSpineMeshEntries( const ChemCompt* other,
    	   vector< VoxelJunction >& ret ) const
    {
    }
    
    void SpineMesh::matchNeuroMeshEntries( const ChemCompt* other,
    	   vector< VoxelJunction >& ret ) const
    {
    	const NeuroMesh* nm = dynamic_cast< const NeuroMesh* >( other );
    	assert( nm );
    	for ( unsigned int i = 0; i < spines_.size(); ++i ) {
    		double xda = spines_[i].rootArea() / spines_[i].diffusionLength();
    		ret.push_back( VoxelJunction( i, spines_[i].parent(), xda ) );
    		ret.back().firstVol = spines_[i].volume();
    		ret.back().secondVol = 
    				nm->getMeshEntryVolume( spines_[i].parent() );
    	}
    }
    
    void SpineMesh::matchCubeMeshEntries( const ChemCompt* other,
    	   vector< VoxelJunction >& ret ) const
    {
    	for( unsigned int i = 0; i < spines_.size(); ++i ) {
    		const SpineEntry& se = spines_[i];
    		se.matchCubeMeshEntriesToHead( other, i, surfaceGranularity_, ret );
    	}
    }